Compare commits

...

15 Commits

Author SHA1 Message Date
github-actions[bot]
5e3ab732df [Backport release-1.4] Feat: add the API for querying the image info (#4211)
* Feat: add the API for querying the image info

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit e257cc6658)

* Fix: the code style

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit 45e183b44b)

Co-authored-by: barnettZQG <barnett.zqg@gmail.com>
2022-06-21 15:05:15 +08:00
github-actions[bot]
62d5507499 Fix: cue patch remove temp var (#4208)
Signed-off-by: Somefive <yd219913@alibaba-inc.com>
(cherry picked from commit 660e89b3a0)

Co-authored-by: Somefive <yd219913@alibaba-inc.com>
2022-06-20 17:38:34 +08:00
github-actions[bot]
c0daf688a6 Fix: clear namespace for cluster scoped resource for dispatching (#4195)
Signed-off-by: Somefive <yd219913@alibaba-inc.com>
(cherry picked from commit 7c9de1b071)

Co-authored-by: Somefive <yd219913@alibaba-inc.com>
2022-06-16 14:50:44 +08:00
github-actions[bot]
48d19a2427 [Backport release-1.4] Feat: cli addon add registry add more git types (#4191)
* add more git types

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
(cherry picked from commit 1d6a5eea22)

* fix comments

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>

fix comments

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
(cherry picked from commit 91122432ec)

Co-authored-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
2022-06-16 12:23:15 +08:00
github-actions[bot]
4da8d49e60 Fix: fix the annotation for APIService (#4190)
Make the annatation for cert-manger be the same as the new version
secret

Signed-off-by: Zheng Xi Zhou <zhengxi.zzx@alibaba-inc.com>
(cherry picked from commit 62ef7b7f99)

Co-authored-by: Zheng Xi Zhou <zhengxi.zzx@alibaba-inc.com>
2022-06-16 11:02:35 +08:00
github-actions[bot]
4db9e89816 Fix: enhance CLI for managing OCM clusters (#4178)
Signed-off-by: Somefive <yd219913@alibaba-inc.com>
(cherry picked from commit 0662e2a79d)

Co-authored-by: Somefive <yd219913@alibaba-inc.com>
2022-06-15 11:23:12 +08:00
github-actions[bot]
667053409d Fix: fix trait customStatus error when controlPlanOnly=true (#4177)
Signed-off-by: fourierr <maxiangboo@qq.com>
(cherry picked from commit 38648fcf30)

Co-authored-by: fourierr <maxiangboo@qq.com>
2022-06-15 11:22:15 +08:00
github-actions[bot]
eb9ddaabd3 [Backport release-1.4] Feat: optimize the API that list and detail definition (#4160)
* Fix: ignore the error that the definition API schema is not exist

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit 855716d989)

* Fix: disable the cache when listing the definitions

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit f25882974d)

Co-authored-by: barnettZQG <barnett.zqg@gmail.com>
2022-06-13 13:25:41 +08:00
github-actions[bot]
f11a94612f Feat: support insecure cluster (#4159)
Signed-off-by: Somefive <yd219913@alibaba-inc.com>
(cherry picked from commit 8abedf3005)

Co-authored-by: Somefive <yd219913@alibaba-inc.com>
2022-06-13 13:15:34 +08:00
github-actions[bot]
56f9d7cb9c [Backport release-1.4] Fix: mongoDB datastore can't list special email user(#4104) (#4148)
* Add description column to vela trait and component command (#4107)

Signed-off-by: Holger Protzek <holger.protzek@springernature.com>
Signed-off-by: fengkang <fengkangb@digitalchina.com>
(cherry picked from commit 9c57ae2a15)

* Fix: mongoDB datastore can't list special email user(#4104)

Signed-off-by: fengkang <fengkangb@digitalchina.com>
(cherry picked from commit ec07790935)

* Fix: mongoDB datastore can't list special email user(#4104)
     change the function name from verifyUserValue to verifyValue
     add test case to test kubeapi.go:87

Signed-off-by: fengkang <fengkangb@digitalchina.com>
(cherry picked from commit 4c55e0688f)

* Fix: mongoDB datastore can't list special email user(#4104)
     change the function name from verifyUserValue to verifyValue
     add test case to test kubeapi.go:87
     add delete test case

Signed-off-by: fengkang <fengkangb@digitalchina.com>
(cherry picked from commit b2e76001c9)

* Fix: mongoDB datastore can't list special email user(#4104)
     optimize the test case

Signed-off-by: fengkang <fengkangb@digitalchina.com>
(cherry picked from commit a63c96fae1)

* Fix: mongoDB datastore can't list special email user(#4104)
     optimize the test case use user
     change all verify timing in kubeapi

Signed-off-by: fengkang <fengkangb@digitalchina.com>
(cherry picked from commit 2ede4f7b0c)

* Fix: mongoDB datastore can't list special email user(#4104)

Signed-off-by: fengkang <fengkangb@digitalchina.com>
(cherry picked from commit 356150642f)

* Fix: mongoDB datastore can't list special email user(#4104)

Signed-off-by: fengkang <fengkangb@digitalchina.com>
(cherry picked from commit 48a9e55937)

Co-authored-by: Holger Protzek <3481523+hprotzek@users.noreply.github.com>
Co-authored-by: fengkang01 <fengkangb@digitalchina.com>
2022-06-10 15:33:53 +08:00
github-actions[bot]
fbbc666019 [Backport release-1.4] Fix: api not exist don't break whole query process (#4137)
* make resource tree more

resourceTree more robust

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
(cherry picked from commit 327ec35cf4)

* log the error

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
(cherry picked from commit 1136afe78c)

Co-authored-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
2022-06-09 11:36:57 +08:00
github-actions[bot]
d0788254cb Fix: vela addon registry get panic (#4136)
Signed-off-by: ZhongsJie <zhongsjie@gmail.com>
(cherry picked from commit 0d329e394e)

Co-authored-by: ZhongsJie <zhongsjie@gmail.com>
2022-06-09 10:19:28 +08:00
github-actions[bot]
c72a6aef87 Chore(deps): Bump github.com/containerd/containerd from 1.5.10 to 1.5.13 (#4125)
Bumps [github.com/containerd/containerd](https://github.com/containerd/containerd) from 1.5.10 to 1.5.13.
- [Release notes](https://github.com/containerd/containerd/releases)
- [Changelog](https://github.com/containerd/containerd/blob/main/RELEASES.md)
- [Commits](https://github.com/containerd/containerd/compare/v1.5.10...v1.5.13)

---
updated-dependencies:
- dependency-name: github.com/containerd/containerd
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
(cherry picked from commit 9982c7ceaa)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-08 12:56:05 +08:00
github-actions[bot]
195b7fe0c7 [Backport release-1.4] Fix: bump oamdev/kube-webhook-certgen to v2.4.1 to support arm64 (#4117)
* Fix: split the image build process to make it faster

Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com>
(cherry picked from commit 339977e874)

* Fix: bump oamdev/kube-webhook-certgen to v2.4.1 to support arm64

Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com>
(cherry picked from commit dc054e2ce2)

Co-authored-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com>
2022-06-05 15:10:48 +08:00
github-actions[bot]
33c9e3b170 Fix: change the image name in ghcr to align with docker image registry (#4111)
Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com>
(cherry picked from commit 71776c374b)

Co-authored-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com>
2022-06-04 14:19:21 +08:00
47 changed files with 977 additions and 835 deletions

View File

@@ -15,7 +15,7 @@ env:
ARTIFACT_HUB_REPOSITORY_ID: ${{ secrets.ARTIFACT_HUB_REPOSITORY_ID }}
jobs:
publish-images:
publish-core-images:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
@@ -55,12 +55,8 @@ jobs:
with:
driver-opts: image=moby/buildkit:master
- name: Build & Pushing vela-core for ACR
run: |
docker build --build-arg GOPROXY=https://proxy.golang.org --build-arg VERSION=${{ steps.get_version.outputs.VERSION }} --build-arg GITVERSION=git-${{ steps.vars.outputs.git_revision }} -t kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-core:${{ steps.get_version.outputs.VERSION }} .
docker push kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-core:${{ steps.get_version.outputs.VERSION }}
- uses: docker/build-push-action@v2
name: Build & Pushing vela-core for Dockerhub and GHCR
name: Build & Pushing vela-core for Dockerhub, GHCR and ACR
with:
context: .
file: Dockerfile
@@ -75,36 +71,11 @@ jobs:
GOPROXY=https://proxy.golang.org
tags: |-
docker.io/oamdev/vela-core:${{ steps.get_version.outputs.VERSION }}
ghcr.io/${{ github.repository }}/vela-core:${{ steps.get_version.outputs.VERSION }}
ghcr.io/${{ github.repository_owner }}/oamdev/vela-core:${{ steps.get_version.outputs.VERSION }}
kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-core:${{ steps.get_version.outputs.VERSION }}
- name: Build & Pushing vela-apiserver for ACR
run: |
docker build --build-arg GOPROXY=https://proxy.golang.org --build-arg VERSION=${{ steps.get_version.outputs.VERSION }} --build-arg GITVERSION=git-${{ steps.vars.outputs.git_revision }} -t kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-apiserver:${{ steps.get_version.outputs.VERSION }} -f Dockerfile.apiserver .
docker push kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-apiserver:${{ steps.get_version.outputs.VERSION }}
- uses: docker/build-push-action@v2
name: Build & Pushing vela-apiserver for Dockerhub and GHCR
with:
context: .
file: Dockerfile.apiserver
labels: |-
org.opencontainers.image.source=https://github.com/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
build-args: |
GITVERSION=git-${{ steps.vars.outputs.git_revision }}
VERSION=${{ steps.get_version.outputs.VERSION }}
GOPROXY=https://proxy.golang.org
tags: |-
docker.io/oamdev/vela-apiserver:${{ steps.get_version.outputs.VERSION }}
ghcr.io/${{ github.repository }}/vela-apiserver:${{ steps.get_version.outputs.VERSION }}
- name: Build & Pushing vela CLI for ACR
run: |
docker build --build-arg GOPROXY=https://proxy.golang.org --build-arg VERSION=${{ steps.get_version.outputs.VERSION }} --build-arg GITVERSION=git-${{ steps.vars.outputs.git_revision }} -t kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-cli:${{ steps.get_version.outputs.VERSION }} -f Dockerfile.cli .
docker push kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-cli:${{ steps.get_version.outputs.VERSION }}
- uses: docker/build-push-action@v2
name: Build & Pushing CLI for Dockerhub and GHCR
name: Build & Pushing CLI for Dockerhub, GHCR and ACR
with:
context: .
file: Dockerfile.cli
@@ -119,10 +90,70 @@ jobs:
GOPROXY=https://proxy.golang.org
tags: |-
docker.io/oamdev/vela-cli:${{ steps.get_version.outputs.VERSION }}
ghcr.io/${{ github.repository }}/vela-cli:${{ steps.get_version.outputs.VERSION }}
ghcr.io/${{ github.repository_owner }}/oamdev/vela-cli:${{ steps.get_version.outputs.VERSION }}
kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-cli:${{ steps.get_version.outputs.VERSION }}
publish-addon-images:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Get the version
id: get_version
run: |
VERSION=${GITHUB_REF#refs/tags/}
if [[ ${GITHUB_REF} == "refs/heads/master" ]]; then
VERSION=latest
fi
echo ::set-output name=VERSION::${VERSION}
- name: Get git revision
id: vars
shell: bash
run: |
echo "::set-output name=git_revision::$(git rev-parse --short HEAD)"
- name: Login ghcr.io
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login docker.io
uses: docker/login-action@v1
with:
registry: docker.io
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login Alibaba Cloud ACR
uses: docker/login-action@v1
with:
registry: kubevela-registry.cn-hangzhou.cr.aliyuncs.com
username: ${{ secrets.ACR_USERNAME }}@aliyun-inner.com
password: ${{ secrets.ACR_PASSWORD }}
- uses: docker/setup-qemu-action@v1
- uses: docker/setup-buildx-action@v1
with:
driver-opts: image=moby/buildkit:master
- uses: docker/build-push-action@v2
name: Build & Pushing runtime rollout for Dockerhub and GHCR
name: Build & Pushing vela-apiserver for Dockerhub, GHCR and ACR
with:
context: .
file: Dockerfile.apiserver
labels: |-
org.opencontainers.image.source=https://github.com/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
build-args: |
GITVERSION=git-${{ steps.vars.outputs.git_revision }}
VERSION=${{ steps.get_version.outputs.VERSION }}
GOPROXY=https://proxy.golang.org
tags: |-
docker.io/oamdev/vela-apiserver:${{ steps.get_version.outputs.VERSION }}
ghcr.io/${{ github.repository_owner }}/oamdev/vela-apiserver:${{ steps.get_version.outputs.VERSION }}
kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-apiserver:${{ steps.get_version.outputs.VERSION }}
- uses: docker/build-push-action@v2
name: Build & Pushing runtime rollout Dockerhub, GHCR and ACR
with:
context: .
file: runtime/rollout/Dockerfile
@@ -137,7 +168,7 @@ jobs:
GOPROXY=https://proxy.golang.org
tags: |-
docker.io/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }}
ghcr.io/${{ github.repository }}/vela-rollout:${{ steps.get_version.outputs.VERSION }}
ghcr.io/${{ github.repository_owner }}/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }}
kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }}
publish-charts:

View File

@@ -106,7 +106,7 @@ metadata:
name: v1alpha1.cluster.core.oam.dev
annotations:
{{- if and .Values.multicluster.clusterGateway.secureTLS.enabled .Values.multicluster.clusterGateway.secureTLS.certManager.enabled }}
cert-manager.io/inject-ca-from: "{{ .Release.Namespace }}/{{ template "kubevela.fullname" . }}-cluster-gateway-tls"
cert-manager.io/inject-ca-from: "{{ .Release.Namespace }}/{{ template "kubevela.fullname" . }}-cluster-gateway-tls-v2"
{{- end }}
labels:
api: cluster-extension-apiserver

View File

@@ -20,6 +20,7 @@ spec:
import (
"encoding/base64"
"encoding/json"
"strconv"
)
output: {
@@ -42,21 +43,29 @@ spec:
if parameter.auth == _|_ {
type: "Opaque"
}
if parameter.auth != _|_ {
stringData: ".dockerconfigjson": json.Marshal({
auths: "\(parameter.registry)": {
username: parameter.auth.username
password: parameter.auth.password
if parameter.auth.email != _|_ {
email: parameter.auth.email
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))
}
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
// +usage=Image registry FQDN, such as: index.docker.io
registry: string
// +usage=Authenticate the image registry
auth?: {
@@ -67,6 +76,10 @@ spec:
// +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
}
workload:
type: autodetects.core.oam.dev

View File

@@ -226,7 +226,7 @@ admissionWebhooks:
enabled: true
image:
repository: oamdev/kube-webhook-certgen
tag: v2.4.0
tag: v2.4.1
pullPolicy: IfNotPresent
nodeSelector: {}
affinity: {}

View File

@@ -20,6 +20,7 @@ spec:
import (
"encoding/base64"
"encoding/json"
"strconv"
)
output: {
@@ -42,21 +43,29 @@ spec:
if parameter.auth == _|_ {
type: "Opaque"
}
if parameter.auth != _|_ {
stringData: ".dockerconfigjson": json.Marshal({
auths: "\(parameter.registry)": {
username: parameter.auth.username
password: parameter.auth.password
if parameter.auth.email != _|_ {
email: parameter.auth.email
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))
}
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
// +usage=Image registry FQDN, such as: index.docker.io
registry: string
// +usage=Authenticate the image registry
auth?: {
@@ -67,6 +76,10 @@ spec:
// +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
}
workload:
type: autodetects.core.oam.dev

View File

@@ -203,7 +203,7 @@ admissionWebhooks:
enabled: true
image:
repository: oamdev/kube-webhook-certgen
tag: v2.4.0
tag: v2.4.1
pullPolicy: IfNotPresent
nodeSelector: {}
affinity: {}

6
go.mod
View File

@@ -16,7 +16,7 @@ require (
github.com/barnettZQG/inject v0.0.1
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869
github.com/briandowns/spinner v1.11.1
github.com/containerd/containerd v1.5.10
github.com/containerd/containerd v1.5.13
github.com/coreos/go-oidc v2.1.0+incompatible
github.com/coreos/prometheus-operator v0.41.1
github.com/crossplane/crossplane-runtime v0.14.1-0.20210722005935-0b469fcc77cd
@@ -46,7 +46,7 @@ require (
github.com/hashicorp/hcl/v2 v2.9.1
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174
github.com/imdario/mergo v0.3.12
github.com/kubevela/prism v1.4.0
github.com/kubevela/prism v1.4.1-0.20220613123457-94f1190f87c2
github.com/kyokomi/emoji v2.2.4+incompatible
github.com/mitchellh/hashstructure/v2 v2.0.1
github.com/oam-dev/cluster-gateway v1.4.0
@@ -122,7 +122,7 @@ require (
github.com/Masterminds/sprig/v3 v3.2.2 // indirect
github.com/Masterminds/squirrel v1.5.2 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/Microsoft/hcsshim v0.8.23 // indirect
github.com/Microsoft/hcsshim v0.8.24 // indirect
github.com/NYTimes/gziphandler v1.1.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect

15
go.sum
View File

@@ -178,8 +178,8 @@ github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
github.com/Microsoft/hcsshim v0.8.23 h1:47MSwtKGXet80aIn+7h4YI6fwPmwIghAnsx2aOUrG2M=
github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
github.com/Microsoft/hcsshim v0.8.24 h1:jP+GMeRXIR1sH1kG4lJr9ShmSjVrua5jmFZDtfYGkn4=
github.com/Microsoft/hcsshim v0.8.24/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
@@ -412,8 +412,9 @@ github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1
github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
github.com/containerd/cgroups v1.0.1 h1:iJnMvco9XGvKUvNQkv88bE4uJXxRQH18efbKo9w5vHQ=
github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU=
github.com/containerd/cgroups v1.0.3 h1:ADZftAkglvCiD44c77s5YmMqaP2pzVCFZvBmAlBdAP4=
github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
@@ -435,8 +436,8 @@ github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoT
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
github.com/containerd/containerd v1.5.2/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
github.com/containerd/containerd v1.5.10 h1:3cQ2uRVCkJVcx5VombsE7105Gl9Wrl7ORAO3+4+ogf4=
github.com/containerd/containerd v1.5.10/go.mod h1:fvQqCfadDGga5HZyn3j4+dx56qj2I9YwBrlSdalvJYQ=
github.com/containerd/containerd v1.5.13 h1:XqvKw9i4P7/mFrC3TSM7yV5cwFZ9avXe6M3YANKnzEE=
github.com/containerd/containerd v1.5.13/go.mod h1:3AlCrzKROjIuP3JALsY14n8YtntaUDBu7vek+rPN5Vc=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@@ -1343,8 +1344,8 @@ 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/prism v1.4.0 h1:wYCKXA3p9YpkcSsZjGnSEGBVL+3bPoZNEt4DYs3IxW4=
github.com/kubevela/prism v1.4.0/go.mod h1:RP69+bRb57Occer6BeeF5zK3hrD1IhnYf2RNRsIdh9E=
github.com/kubevela/prism v1.4.1-0.20220613123457-94f1190f87c2 h1:TaHlO4raKI3ehVSYY8QixYMHdI0VwKHY1KPNWcUre3I=
github.com/kubevela/prism v1.4.1-0.20220613123457-94f1190f87c2/go.mod h1:RP69+bRb57Occer6BeeF5zK3hrD1IhnYf2RNRsIdh9E=
github.com/kulti/thelper v0.4.0/go.mod h1:vMu2Cizjy/grP+jmsvOFDx1kYP6+PD1lqg4Yu5exl2U=
github.com/kunwardeep/paralleltest v1.0.2/go.mod h1:ZPqNm1fVHPllh5LPVujzbVz1JN2GhLxSfY+oqUsvG30=
github.com/kunwardeep/paralleltest v1.0.3/go.mod h1:vLydzomDFpk7yu5UX02RmP0H8QfRPOV/oFhWN85Mjb4=

View File

@@ -18,7 +18,6 @@ package model
import (
"fmt"
"strings"
"time"
"github.com/form3tech-oss/jwt-go"
@@ -63,17 +62,17 @@ func (u *User) ShortTableName() string {
// PrimaryKey return custom primary key
func (u *User) PrimaryKey() string {
return verifyUserValue(u.Name)
return u.Name
}
// Index return custom index
func (u *User) Index() map[string]string {
index := make(map[string]string)
if u.Name != "" {
index["name"] = verifyUserValue(u.Name)
index["name"] = u.Name
}
if u.Email != "" {
index["email"] = verifyUserValue(u.Email)
index["email"] = u.Email
}
return index
}
@@ -99,14 +98,14 @@ func (u *ProjectUser) ShortTableName() string {
// PrimaryKey return custom primary key
func (u *ProjectUser) PrimaryKey() string {
return fmt.Sprintf("%s-%s", u.ProjectName, verifyUserValue(u.Username))
return fmt.Sprintf("%s-%s", u.ProjectName, u.Username)
}
// Index return custom index
func (u *ProjectUser) Index() map[string]string {
index := make(map[string]string)
if u.Username != "" {
index["username"] = verifyUserValue(u.Username)
index["username"] = u.Username
}
if u.ProjectName != "" {
index["projectName"] = u.ProjectName
@@ -114,12 +113,6 @@ func (u *ProjectUser) Index() map[string]string {
return index
}
func verifyUserValue(v string) string {
s := strings.ReplaceAll(v, "@", "-")
s = strings.ReplaceAll(s, " ", "-")
return strings.ToLower(s)
}
// CustomClaims is the custom claims
type CustomClaims struct {
Username string `json:"username"`

View File

@@ -29,6 +29,12 @@ func init() {
RegisterModel(&WorkflowRecord{})
}
// Finished means the workflow record is finished
const Finished = "true"
// UnFinished means the workflow record is not finished
const UnFinished = "false"
// Workflow application delivery database model
type Workflow struct {
BaseModel

View File

@@ -507,14 +507,14 @@ func (c *applicationServiceImpl) UpdateApplication(ctx context.Context, app *mod
func (c *applicationServiceImpl) ListRecords(ctx context.Context, appName string) (*apisv1.ListWorkflowRecordsResponse, error) {
var record = model.WorkflowRecord{
AppPrimaryKey: appName,
Finished: "false",
Finished: model.UnFinished,
}
records, err := c.Store.List(ctx, &record, &datastore.ListOptions{})
if err != nil {
return nil, err
}
if len(records) == 0 {
record.Finished = "true"
record.Finished = model.Finished
records, err = c.Store.List(ctx, &record, &datastore.ListOptions{
Page: 1,
PageSize: 1,

View File

@@ -40,7 +40,6 @@ import (
"github.com/oam-dev/kubevela/pkg/apiserver/domain/repository"
"github.com/oam-dev/kubevela/pkg/apiserver/infrastructure/datastore"
v1 "github.com/oam-dev/kubevela/pkg/apiserver/interfaces/api/dto/v1"
"github.com/oam-dev/kubevela/pkg/apiserver/utils"
"github.com/oam-dev/kubevela/pkg/apiserver/utils/bcode"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/util"
@@ -78,7 +77,7 @@ var _ = Describe("Test application service function", func() {
projectService = &projectServiceImpl{Store: ds, K8sClient: k8sClient, RbacService: rbacService}
envService = &envServiceImpl{Store: ds, KubeClient: k8sClient, ProjectService: projectService}
workflowService = &workflowServiceImpl{Store: ds, EnvService: envService}
definitionService = &definitionServiceImpl{KubeClient: k8sClient, caches: utils.NewMemoryCacheStore(context.Background())}
definitionService = &definitionServiceImpl{KubeClient: k8sClient}
envBindingService = &envBindingServiceImpl{Store: ds, EnvService: envService, WorkflowService: workflowService, KubeClient: k8sClient, DefinitionService: definitionService}
targetService = &targetServiceImpl{Store: ds, K8sClient: k8sClient}
appService = &applicationServiceImpl{

View File

@@ -60,7 +60,10 @@ var _ = Describe("Test cluster service function", func() {
secret.Name = name
secret.Namespace = prismclusterv1alpha1.StorageNamespace
secret.SetAnnotations(map[string]string{prismclusterv1alpha1.AnnotationClusterAlias: alias})
secret.SetLabels(map[string]string{clustergatewaycommon.LabelKeyClusterCredentialType: string(clustergatewayv1alpha1.CredentialTypeX509Certificate)})
secret.SetLabels(map[string]string{
clustergatewaycommon.LabelKeyClusterEndpointType: string(clustergatewayv1alpha1.ClusterEndpointTypeConst),
clustergatewaycommon.LabelKeyClusterCredentialType: string(clustergatewayv1alpha1.CredentialTypeX509Certificate),
})
time.Sleep(time.Second)
return k8sClient.Create(ctx, secret)
}

View File

@@ -21,7 +21,6 @@ import (
"encoding/json"
"fmt"
"sort"
"time"
"github.com/getkin/kin-openapi/openapi3"
"github.com/pkg/errors"
@@ -53,9 +52,11 @@ type DefinitionService interface {
UpdateDefinitionStatus(ctx context.Context, name string, status apisv1.UpdateDefinitionStatusRequest) (*apisv1.DetailDefinitionResponse, error)
}
// DefinitionHidden means the definition can not be used in VelaUX
const DefinitionHidden = "true"
type definitionServiceImpl struct {
KubeClient client.Client `inject:"kubeClient"`
caches *utils.MemoryCacheStore
}
// DefinitionQueryOption define a set of query options
@@ -80,7 +81,7 @@ const (
// NewDefinitionService new definition service
func NewDefinitionService() DefinitionService {
return &definitionServiceImpl{caches: utils.NewMemoryCacheStore(context.Background())}
return &definitionServiceImpl{}
}
func (d *definitionServiceImpl) ListDefinitions(ctx context.Context, ops DefinitionQueryOption) ([]*apisv1.DefinitionBase, error) {
@@ -95,9 +96,6 @@ func (d *definitionServiceImpl) ListDefinitions(ctx context.Context, ops Definit
}
func (d *definitionServiceImpl) listDefinitions(ctx context.Context, list *unstructured.UnstructuredList, kind string, ops DefinitionQueryOption) ([]*apisv1.DefinitionBase, error) {
if mc := d.caches.Get(ops.String()); mc != nil {
return mc.([]*apisv1.DefinitionBase), nil
}
matchLabels := metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
@@ -146,9 +144,6 @@ func (d *definitionServiceImpl) listDefinitions(ctx context.Context, list *unstr
}
defs = append(defs, definition)
}
if ops.AppliedWorkloads == "" {
d.caches.Put(ops.String(), defs, time.Minute*3)
}
return defs, nil
}
@@ -240,30 +235,27 @@ func (d *definitionServiceImpl) DetailDefinition(ctx context.Context, name, defT
if err := d.KubeClient.Get(ctx, k8stypes.NamespacedName{
Namespace: types.DefaultKubeVelaNS,
Name: fmt.Sprintf("%s-schema-%s", defType, name),
}, &cm); err != nil {
if apierrors.IsNotFound(err) {
return nil, bcode.ErrDefinitionNoSchema
}
}, &cm); err != nil && !apierrors.IsNotFound(err) {
return nil, err
}
data, ok := cm.Data[types.OpenapiV3JSONSchema]
if !ok {
return nil, bcode.ErrDefinitionNoSchema
}
schema := &openapi3.Schema{}
if err := schema.UnmarshalJSON([]byte(data)); err != nil {
return nil, err
}
// render default ui schema
defaultUISchema := renderDefaultUISchema(schema)
// patch from custom ui schema
customUISchema := d.renderCustomUISchema(ctx, name, defType, defaultUISchema)
return &apisv1.DetailDefinitionResponse{
definition := &apisv1.DetailDefinitionResponse{
DefinitionBase: *base,
APISchema: schema,
UISchema: customUISchema,
}, nil
}
data, ok := cm.Data[types.OpenapiV3JSONSchema]
if ok {
schema := &openapi3.Schema{}
if err := schema.UnmarshalJSON([]byte(data)); err != nil {
return nil, err
}
definition.APISchema = schema
// render default ui schema
defaultUISchema := renderDefaultUISchema(schema)
// patch from custom ui schema
definition.UISchema = d.renderCustomUISchema(ctx, name, defType, defaultUISchema)
}
return definition, nil
}
func (d *definitionServiceImpl) renderCustomUISchema(ctx context.Context, name, defType string, defaultSchema []*utils.UIParameter) []*utils.UIParameter {
@@ -355,7 +347,7 @@ func (d *definitionServiceImpl) UpdateDefinitionStatus(ctx context.Context, name
}
if !exist && update.HiddenInUI {
labels := def.GetLabels()
labels[types.LabelDefinitionHidden] = "true"
labels[types.LabelDefinitionHidden] = DefinitionHidden
def.SetLabels(labels)
if err := d.KubeClient.Update(ctx, def); err != nil {
return nil, err

View File

@@ -44,7 +44,7 @@ var _ = Describe("Test namespace service functions", func() {
)
BeforeEach(func() {
definitionService = &definitionServiceImpl{KubeClient: k8sClient, caches: utils.NewMemoryCacheStore(context.TODO())}
definitionService = &definitionServiceImpl{KubeClient: k8sClient}
err := k8sClient.Create(context.Background(), &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: "vela-system",
@@ -215,7 +215,6 @@ var _ = Describe("Test namespace service functions", func() {
It("Test update ui schema", func() {
du := &definitionServiceImpl{
KubeClient: k8sClient,
caches: utils.NewMemoryCacheStore(context.Background()),
}
cdata, err := ioutil.ReadFile("./testdata/workflowstep-apply-object.yaml")
Expect(err).Should(Succeed())
@@ -235,7 +234,6 @@ var _ = Describe("Test namespace service functions", func() {
It("Test update status of the definition", func() {
du := &definitionServiceImpl{
KubeClient: k8sClient,
caches: utils.NewMemoryCacheStore(context.Background()),
}
detail, err := du.UpdateDefinitionStatus(context.TODO(), "apply-object", v1.UpdateDefinitionStatusRequest{
DefinitionType: "workflowstep",

View File

@@ -27,7 +27,6 @@ import (
"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"
)
var _ = Describe("Test envBindingService functions", func() {
@@ -54,7 +53,7 @@ var _ = Describe("Test envBindingService functions", func() {
projectService := &projectServiceImpl{Store: ds, K8sClient: k8sClient, RbacService: rbacService}
envService = &envServiceImpl{Store: ds, KubeClient: k8sClient, ProjectService: projectService}
workflowService = &workflowServiceImpl{Store: ds, KubeClient: k8sClient, EnvService: envService}
definitionService = &definitionServiceImpl{KubeClient: k8sClient, caches: utils.NewMemoryCacheStore(context.TODO())}
definitionService = &definitionServiceImpl{KubeClient: k8sClient}
envBindingService = &envBindingServiceImpl{Store: ds, WorkflowService: workflowService, DefinitionService: definitionService, KubeClient: k8sClient, EnvService: envService}
envBindingDemo1 = apisv1.EnvBinding{
Name: "envbinding-dev",

View File

@@ -0,0 +1,228 @@
/*
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 service
import (
"context"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"net"
"net/http"
"strings"
"time"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/types"
v1 "github.com/oam-dev/kubevela/pkg/apiserver/interfaces/api/dto/v1"
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
)
// NewImageService create a image service instance
func NewImageService() ImageService {
return &imageImpl{}
}
// ImageService the image service provide some handler functions about the docker image
type ImageService interface {
ListImageRepos(ctx context.Context, project string) ([]v1.ImageRegistry, error)
GetImageInfo(ctx context.Context, project, secretName, imageName string) v1.ImageInfo
}
type imageImpl struct {
K8sClient client.Client `inject:"kubeClient"`
}
// ListImageRepos list the image repositories via user configuration
func (i *imageImpl) ListImageRepos(ctx context.Context, project string) ([]v1.ImageRegistry, error) {
var secrets corev1.SecretList
if err := i.K8sClient.List(ctx, &secrets, client.InNamespace(types.DefaultKubeVelaNS),
client.MatchingLabels{
types.LabelConfigCatalog: types.VelaCoreConfig,
types.LabelConfigType: types.ImageRegistry,
}); err != nil {
return nil, err
}
var repos []v1.ImageRegistry
for _, secret := range secrets.Items {
if secret.Labels[types.LabelConfigProject] == "" || secret.Labels[types.LabelConfigProject] == project {
repos = append(repos, v1.ImageRegistry{
Name: secret.Name,
SecretName: secret.Name,
Domain: secret.Labels[types.LabelConfigIdentifier],
})
}
}
return repos, nil
}
// GetImageInfo get the image info from image registry
func (i *imageImpl) GetImageInfo(ctx context.Context, project, secretName, imageName string) v1.ImageInfo {
var imageInfo = v1.ImageInfo{
Name: imageName,
}
ref, err := name.ParseReference(imageName)
if err != nil {
imageInfo.Message = "The image name is invalid"
return imageInfo
}
registryDomain := ref.Context().RegistryStr()
imageInfo.Registry = registryDomain
var secrets corev1.SecretList
if err := i.K8sClient.List(ctx, &secrets, client.InNamespace(types.DefaultKubeVelaNS),
client.MatchingLabels{
types.LabelConfigCatalog: types.VelaCoreConfig,
types.LabelConfigType: types.ImageRegistry,
types.LabelConfigIdentifier: registryDomain,
}); err != nil {
log.Logger.Warnf("fail to list the docker registries, %s", err.Error())
}
var selectSecret []*corev1.Secret
var selectSecretNames []string
// get info with specified secret
if secretName != "" {
for i, secret := range secrets.Items {
if secret.Labels[types.LabelConfigProject] == "" || secret.Labels[types.LabelConfigProject] == project {
if secretName == secret.Name {
selectSecret = append(selectSecret, &secrets.Items[i])
selectSecretNames = append(selectSecretNames, secret.Name)
break
}
}
}
}
// get info with the secret which match the registry domain
if selectSecret == nil {
for i, secret := range secrets.Items {
if secret.Labels[types.LabelConfigProject] == "" || secret.Labels[types.LabelConfigProject] == project {
if secret.Labels[types.LabelConfigIdentifier] == registryDomain {
selectSecret = append(selectSecret, &secrets.Items[i])
selectSecretNames = append(selectSecretNames, secret.Name)
}
}
}
}
var username, password string
var insecure = false
var useHTTP = false
imageInfo.SecretNames = selectSecretNames
if len(selectSecret) > 0 {
insecure, useHTTP, username, password = getAccountFromSecret(*selectSecret[0], registryDomain)
}
err = getImageInfo(imageName, insecure, useHTTP, username, password, &imageInfo)
if err != nil {
imageInfo.Message = fmt.Sprintf("Fail to get the image info:%s", err.Error())
}
return imageInfo
}
// getAccountFromSecret get the username and password from the secret of `kubernetes.io/dockerconfigjson` type
// refer: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
func getAccountFromSecret(secret corev1.Secret, registryDomain string) (insecure, useHTTP bool, username, password string) {
if secret.Data != nil {
// If users use the self-signed certificate, enable the insecure-skip-verify
insecure = string(secret.Data["insecure-skip-verify"]) == "true"
useHTTP = string(secret.Data["protocol-use-http"]) == "true"
conf := secret.Data[".dockerconfigjson"]
if len(conf) > 0 {
var authConfig map[string]map[string]map[string]string
if err := json.Unmarshal(conf, &authConfig); err != nil {
log.Logger.Warnf("fail to unmarshal the secret %s , %s", secret.Name, err.Error())
return
}
if authConfig != nil && authConfig["auths"] != nil && authConfig["auths"][registryDomain] != nil {
data := authConfig["auths"][registryDomain]
username = data["username"]
password = data["password"]
}
}
}
return
}
func getImageInfo(imageName string, insecure, useHTTP bool, username, password string, info *v1.ImageInfo) error {
var options []remote.Option
if username != "" || password != "" {
basic := &authn.Basic{
Username: username,
Password: password,
}
options = append(options, remote.WithAuth(basic))
}
if insecure {
options = append(options, remote.WithTransport(&http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
// By default we wrap the transport in retries, so reduce the
// default dial timeout to 5s to avoid 5x 30s of connection
// timeouts when doing the "ping" on certain http registries.
Timeout: 5 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
// #nosec G402
TLSClientConfig: &tls.Config{InsecureSkipVerify: insecure},
}))
}
var parseOptions []name.Option
if useHTTP {
parseOptions = append(parseOptions, name.Insecure)
}
var err error
ref, err := name.ParseReference(imageName, parseOptions...)
if err != nil {
return err
}
image, err := remote.Image(ref, options...)
if err != nil {
if strings.Contains(err.Error(), "incorrect username or password") {
return fmt.Errorf("incorrect username or password")
}
var terr *transport.Error
if errors.As(err, &terr) {
fmt.Println(terr)
}
return err
}
info.Manifest, err = image.Manifest()
if err != nil {
return fmt.Errorf("fail to get the manifest:%w", err)
}
info.Info, err = image.ConfigFile()
if err != nil {
return fmt.Errorf("fail to get the config:%w", err)
}
for _, l := range info.Manifest.Layers {
info.Size += l.Size
}
info.Size += info.Manifest.Config.Size
return nil
}

View File

@@ -0,0 +1,67 @@
/*
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 service
import (
"testing"
"gotest.tools/assert"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
velatypes "github.com/oam-dev/kubevela/apis/types"
v1 "github.com/oam-dev/kubevela/pkg/apiserver/interfaces/api/dto/v1"
)
func TestGetImageInfo(t *testing.T) {
s2 := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "s2",
Namespace: velatypes.DefaultKubeVelaNS,
Labels: map[string]string{
velatypes.LabelConfigCatalog: velatypes.VelaCoreConfig,
velatypes.LabelConfigType: velatypes.ImageRegistry,
velatypes.LabelConfigProject: "",
velatypes.LabelConfigIdentifier: "index.docker.io",
},
},
Data: map[string][]byte{
"insecure-skip-verify": []byte("true"),
".dockerconfigjson": []byte(`{"auths":{"index.docker.io":{"auth":"aHlicmlkY2xvdWRAcHJvZC5YTEyMw==","username":"xxx","password":"yyy"}}}`),
},
}
insecure, useHTTP, user, pass := getAccountFromSecret(*s2, "index.docker.io")
assert.DeepEqual(t, user, "xxx")
assert.DeepEqual(t, pass, "yyy")
assert.DeepEqual(t, insecure, true)
assert.DeepEqual(t, useHTTP, false)
var cf v1.ImageInfo
// Test the public image
err := getImageInfo("nginx", false, false, "", "", &cf)
assert.DeepEqual(t, err, nil)
assert.DeepEqual(t, cf.Info.Config.Entrypoint, []string{"/docker-entrypoint.sh"})
// Test the private image
err = getImageInfo("nginx424ru823-should-not-existed", false, false, "abc", "efg", &cf)
assert.DeepEqual(t, err.Error(), "incorrect username or password")
err = getImageInfo("text.registry/test-image", false, false, "", "", &cf)
assert.DeepEqual(t, err != nil, true)
}

View File

@@ -18,15 +18,12 @@ package service
import (
"context"
"encoding/json"
"errors"
"fmt"
"strings"
"github.com/google/go-containerregistry/pkg/name"
terraformtypes "github.com/oam-dev/terraform-controller/api/types"
terraformapi "github.com/oam-dev/terraform-controller/api/v1beta1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -41,7 +38,6 @@ import (
"github.com/oam-dev/kubevela/pkg/apiserver/utils/bcode"
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
"github.com/oam-dev/kubevela/pkg/multicluster"
image "github.com/oam-dev/kubevela/pkg/utils/imageregistry"
)
// ProjectService project manage service.
@@ -59,7 +55,6 @@ type ProjectService interface {
UpdateProjectUser(ctx context.Context, projectName string, userName string, req apisv1.UpdateProjectUserRequest) (*apisv1.ProjectUserBase, error)
Init(ctx context.Context) error
GetConfigs(ctx context.Context, projectName, configType string) ([]*apisv1.Config, error)
ValidateImage(ctx context.Context, projectName, image string) (*apisv1.ImageResponse, error)
}
type projectServiceImpl struct {
@@ -623,57 +618,3 @@ func retrieveConfigFromApplication(a v1beta1.Application, project string) *apisv
Description: a.Annotations[types.AnnotationConfigDescription],
}
}
func (p *projectServiceImpl) ValidateImage(ctx context.Context, projectName, image string) (*apisv1.ImageResponse, error) {
return validateImage(ctx, p.K8sClient, projectName, image)
}
func validateImage(ctx context.Context, k8sClient client.Client, project, imageName string) (*apisv1.ImageResponse, error) {
var (
secrets v1.SecretList
username string
password string
imagePullSecret string
)
ref, err := name.ParseReference(imageName)
if err != nil {
return nil, err
}
imageURL := ref.Context().RegistryStr()
if err := k8sClient.List(ctx, &secrets, client.InNamespace(types.DefaultKubeVelaNS),
client.MatchingLabels{
types.LabelConfigCatalog: types.VelaCoreConfig,
types.LabelConfigType: types.ImageRegistry,
types.LabelConfigIdentifier: ref.Context().RegistryStr(),
}); err != nil {
return nil, err
}
for _, s := range secrets.Items {
if s.Labels[types.LabelConfigProject] == "" || s.Labels[types.LabelConfigProject] == project {
conf := s.Data[".dockerconfigjson"]
var auths map[string]map[string]map[string]string
if err := json.Unmarshal(conf, &auths); err != nil {
return nil, err
}
imagePullSecret = s.Name
if auths["auths"] != nil && auths["auths"][imageURL] != nil {
data := auths["auths"][imageURL]
username = data["username"]
password = data["password"]
break
}
}
}
existed, err := image.IsExisted(username, password, imageName)
if err != nil {
return nil, err
}
return &apisv1.ImageResponse{
Existed: existed,
Secret: imagePullSecret,
}, nil
}

View File

@@ -18,20 +18,14 @@ package service
import (
"context"
"testing"
"time"
"github.com/google/go-cmp/cmp"
terraformtypes "github.com/oam-dev/terraform-controller/api/types"
terraformapi "github.com/oam-dev/terraform-controller/api/v1beta1"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"gotest.tools/assert"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
@@ -299,331 +293,3 @@ var _ = Describe("Test project service functions", func() {
Expect(roles.Total).Should(BeEquivalentTo(0))
})
})
func TestProjectGetConfigs(t *testing.T) {
s := runtime.NewScheme()
v1beta1.AddToScheme(s)
corev1.AddToScheme(s)
terraformapi.AddToScheme(s)
createdTime, _ := time.Parse(time.UnixDate, "Wed Apr 7 11:06:39 PST 2022")
app1 := &v1beta1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: "a1",
Namespace: velatypes.DefaultKubeVelaNS,
Labels: map[string]string{
model.LabelSourceOfTruth: model.FromInner,
velatypes.LabelConfigCatalog: velatypes.VelaCoreConfig,
velatypes.LabelConfigType: "terraform-provider",
"config.oam.dev/project": "p1",
},
CreationTimestamp: metav1.NewTime(createdTime),
},
Status: common.AppStatus{Phase: common.ApplicationRunning},
}
app2 := &v1beta1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: "a2",
Namespace: velatypes.DefaultKubeVelaNS,
Labels: map[string]string{
model.LabelSourceOfTruth: model.FromInner,
velatypes.LabelConfigCatalog: velatypes.VelaCoreConfig,
velatypes.LabelConfigType: "terraform-provider",
},
CreationTimestamp: metav1.NewTime(createdTime),
},
Status: common.AppStatus{Phase: common.ApplicationRunning},
}
app3 := &v1beta1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: "a3",
Namespace: velatypes.DefaultKubeVelaNS,
Labels: map[string]string{
model.LabelSourceOfTruth: model.FromInner,
velatypes.LabelConfigCatalog: velatypes.VelaCoreConfig,
velatypes.LabelConfigType: "dex-connector",
"config.oam.dev/project": "p3",
},
CreationTimestamp: metav1.NewTime(createdTime),
},
Status: common.AppStatus{Phase: common.ApplicationRunning},
}
provider1 := &terraformapi.Provider{
ObjectMeta: metav1.ObjectMeta{
Name: "provider1",
Namespace: "default",
CreationTimestamp: metav1.NewTime(createdTime),
},
Status: terraformapi.ProviderStatus{
State: terraformtypes.ProviderIsReady,
},
}
provider2 := &terraformapi.Provider{
ObjectMeta: metav1.ObjectMeta{
Name: "provider2",
Namespace: "default",
Labels: map[string]string{
velatypes.LabelConfigCatalog: velatypes.VelaCoreConfig,
},
},
Status: terraformapi.ProviderStatus{
State: terraformtypes.ProviderIsNotReady,
},
}
k8sClient := fake.NewClientBuilder().WithScheme(s).WithObjects(app1, app2, app3, provider1, provider2).Build()
h := &projectServiceImpl{K8sClient: k8sClient}
type args struct {
projectName string
configType string
h ProjectService
}
type want struct {
configs []*apisv1.Config
errMsg string
}
ctx := context.Background()
testcases := []struct {
name string
args args
want want
}{
{
name: "project is matched",
args: args{
projectName: "p1",
configType: "terraform-provider",
h: h,
},
want: want{
configs: []*apisv1.Config{{
ConfigType: "terraform-provider",
Name: "a1",
Project: "p1",
CreatedTime: &createdTime,
ApplicationStatus: "running",
Status: "Ready",
}, {
ConfigType: "terraform-provider",
Name: "a2",
Project: "",
CreatedTime: &createdTime,
ApplicationStatus: "running",
Status: "Ready",
}, {
Name: "provider1",
CreatedTime: &createdTime,
Status: "Ready",
}},
},
},
{
name: "project is not matched",
args: args{
projectName: "p999",
configType: "terraform-provider",
h: h,
},
want: want{
configs: []*apisv1.Config{{
ConfigType: "terraform-provider",
Name: "a2",
Project: "",
CreatedTime: &createdTime,
ApplicationStatus: "running",
Status: "Ready",
}, {
Name: "provider1",
CreatedTime: &createdTime,
Status: "Ready",
}},
},
},
{
name: "config type is empty",
args: args{
projectName: "p3",
configType: "",
h: h,
},
want: want{
configs: []*apisv1.Config{{
ConfigType: "terraform-provider",
Name: "a2",
Project: "",
CreatedTime: &createdTime,
ApplicationStatus: "running",
Status: "Ready",
}, {
ConfigType: "dex-connector",
Name: "a3",
Project: "p3",
CreatedTime: &createdTime,
ApplicationStatus: "running",
Status: "Ready",
}, {
Name: "provider1",
CreatedTime: &createdTime,
Status: "Ready",
}},
},
},
{
name: "config type is dex",
args: args{
projectName: "p3",
configType: "config-dex-connector",
h: h,
},
want: want{
configs: []*apisv1.Config{{
ConfigType: "dex-connector",
Name: "a3",
Project: "p3",
CreatedTime: &createdTime,
ApplicationStatus: "running",
Status: "Ready",
}},
},
},
{
name: "config type is invalid",
args: args{
configType: "xxx",
h: h,
},
want: want{
errMsg: "unsupported config type",
},
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
got, err := tc.args.h.GetConfigs(ctx, tc.args.projectName, tc.args.configType)
if tc.want.errMsg != "" || err != nil {
assert.ErrorContains(t, err, tc.want.errMsg)
}
assert.DeepEqual(t, got, tc.want.configs)
})
}
}
func TestValidateImage(t *testing.T) {
s := runtime.NewScheme()
v1beta1.AddToScheme(s)
corev1.AddToScheme(s)
terraformapi.AddToScheme(s)
s1 := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "s1",
Namespace: velatypes.DefaultKubeVelaNS,
Labels: map[string]string{
velatypes.LabelConfigCatalog: velatypes.VelaCoreConfig,
velatypes.LabelConfigType: velatypes.ImageRegistry,
velatypes.LabelConfigProject: "",
velatypes.LabelConfigIdentifier: "abce34289jwerojwerofaf77.com789",
},
},
Data: map[string][]byte{
".dockerconfigjson": []byte(`{"auths":{"abce34289jwerojwerofaf77.com789":{"auth":"aHlicmlkY2xvdWRAcHJvZC5YTEyMw==","username":"xxx","password":"yyy"}}}`),
},
}
k8sClient1 := fake.NewClientBuilder().WithScheme(s).WithObjects(s1).Build()
h1 := &projectServiceImpl{K8sClient: k8sClient1}
s2 := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "s2",
Namespace: velatypes.DefaultKubeVelaNS,
Labels: map[string]string{
velatypes.LabelConfigCatalog: velatypes.VelaCoreConfig,
velatypes.LabelConfigType: velatypes.ImageRegistry,
velatypes.LabelConfigProject: "",
velatypes.LabelConfigIdentifier: "index.docker.io",
},
},
Data: map[string][]byte{
".dockerconfigjson": []byte(`{"auths":{"index.docker.io":{"auth":"aHlicmlkY2xvdWRAcHJvZC5YTEyMw==","username":"xxx","password":"yyy"}}}`),
},
}
k8sClient2 := fake.NewClientBuilder().WithScheme(s).WithObjects(s2).Build()
h2 := &projectServiceImpl{K8sClient: k8sClient2}
type args struct {
project string
imageName string
h ProjectService
}
type want struct {
resp *apisv1.ImageResponse
errMsg string
}
ctx := context.Background()
testcases := []struct {
name string
args args
want want
}{
{
name: "validate image",
args: args{
project: "p1",
imageName: "nginx",
h: h1,
},
want: want{
resp: &apisv1.ImageResponse{
Existed: true,
},
},
},
{
name: "invalid image",
args: args{
project: "p1",
imageName: "abce34289jwerojwerofaf77.com789/d/e:v1",
h: h1,
},
want: want{
errMsg: "Get",
},
},
{
name: "private docker image",
args: args{
project: "p1",
imageName: "nginx424ru823-should-not-existed",
h: h2,
},
want: want{
errMsg: "incorrect username or password",
},
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
got, err := tc.args.h.ValidateImage(ctx, tc.args.project, tc.args.imageName)
if tc.want.errMsg != "" || err != nil {
assert.ErrorContains(t, err, tc.want.errMsg)
}
assert.DeepEqual(t, got, tc.want.resp)
})
}
}

View File

@@ -202,7 +202,6 @@ var ResourceMaps = map[string]resourceMetadata{
},
"applicationTemplate": {},
"config": {},
"image": {},
},
pathName: "projectName",
},

View File

@@ -50,7 +50,7 @@ func InitServiceBean(c config.Config) []interface{} {
return []interface{}{
clusterService, rbacService, projectService, envService, targetService, workflowService, oamApplicationService,
velaQLService, definitionService, addonService, envBindingService, systemInfoService, helmService, userService,
authenticationService, configService, applicationService, webhookService,
authenticationService, configService, applicationService, webhookService, NewImageService(),
}
}

View File

@@ -75,6 +75,7 @@ func generateName(entity datastore.Entity) string {
// record the old ways here, it'll be migrated
// name := fmt.Sprintf("veladatabase-%s-%s", entity.TableName(), entity.PrimaryKey())
name := fmt.Sprintf("%s-%s", entity.ShortTableName(), entity.PrimaryKey())
name = verifyValue(name)
return strings.ReplaceAll(name, "_", "-")
}
@@ -86,6 +87,9 @@ func (m *kubeapi) generateConfigMap(entity datastore.Entity) *corev1.ConfigMap {
}
labels["table"] = entity.TableName()
labels["primaryKey"] = entity.PrimaryKey()
for k, v := range labels {
labels[k] = verifyValue(v)
}
var configMap = corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: generateName(entity),
@@ -178,6 +182,9 @@ func (m *kubeapi) Put(ctx context.Context, entity datastore.Entity) error {
}
labels["table"] = entity.TableName()
labels["primaryKey"] = entity.PrimaryKey()
for k, v := range labels {
labels[k] = verifyValue(v)
}
entity.SetUpdateTime(time.Now())
var configMap corev1.ConfigMap
if err := m.kubeClient.Get(ctx, types.NamespacedName{Namespace: m.namespace, Name: generateName(entity)}, &configMap); err != nil {
@@ -345,7 +352,7 @@ func (m *kubeapi) List(ctx context.Context, entity datastore.Entity, op *datasto
selector = selector.Add(*rq)
for k, v := range entity.Index() {
rq, err := labels.NewRequirement(k, selection.Equals, []string{v})
rq, err := labels.NewRequirement(k, selection.Equals, []string{verifyValue(v)})
if err != nil {
return nil, datastore.ErrIndexInvalid
}
@@ -353,7 +360,11 @@ func (m *kubeapi) List(ctx context.Context, entity datastore.Entity, op *datasto
}
if op != nil {
for _, inFilter := range op.In {
rq, err := labels.NewRequirement(inFilter.Key, selection.In, inFilter.Values)
var values []string
for _, value := range inFilter.Values {
values = append(values, verifyValue(value))
}
rq, err := labels.NewRequirement(inFilter.Key, selection.In, values)
if err != nil {
log.Logger.Errorf("new list requirement failure %s", err.Error())
return nil, datastore.ErrIndexInvalid
@@ -431,7 +442,7 @@ func (m *kubeapi) Count(ctx context.Context, entity datastore.Entity, filterOpti
return 0, datastore.NewDBError(err)
}
for k, v := range entity.Index() {
rq, err := labels.NewRequirement(k, selection.Equals, []string{v})
rq, err := labels.NewRequirement(k, selection.Equals, []string{verifyValue(v)})
if err != nil {
return 0, datastore.ErrIndexInvalid
}
@@ -439,7 +450,11 @@ func (m *kubeapi) Count(ctx context.Context, entity datastore.Entity, filterOpti
}
if filterOptions != nil {
for _, inFilter := range filterOptions.In {
rq, err := labels.NewRequirement(inFilter.Key, selection.In, inFilter.Values)
var values []string
for _, value := range inFilter.Values {
values = append(values, verifyValue(value))
}
rq, err := labels.NewRequirement(inFilter.Key, selection.In, values)
if err != nil {
return 0, datastore.ErrIndexInvalid
}
@@ -473,3 +488,9 @@ func (m *kubeapi) Count(ctx context.Context, entity datastore.Entity, filterOpti
}
return int64(len(items)), nil
}
func verifyValue(v string) string {
s := strings.ReplaceAll(v, "@", "-")
s = strings.ReplaceAll(s, " ", "-")
return strings.ToLower(s)
}

View File

@@ -246,4 +246,42 @@ var _ = Describe("Test kubeapi datastore driver", func() {
equal := cmp.Equal(err, datastore.ErrRecordNotExist, cmpopts.EquateErrors())
Expect(equal).Should(BeTrue())
})
It("Test verify index", func() {
var usr = model.User{Name: "can@delete", Email: "xxx@xx.com"}
err := kubeStore.Add(context.TODO(), &usr)
Expect(err).ToNot(HaveOccurred())
usr.Email = "change"
err = kubeStore.Put(context.TODO(), &usr)
Expect(err).ToNot(HaveOccurred())
err = kubeStore.Get(context.TODO(), &usr)
Expect(err).Should(BeNil())
diff := cmp.Diff(usr.Email, "change")
Expect(diff).Should(BeEmpty())
list, err := kubeStore.List(context.TODO(), &usr, &datastore.ListOptions{FilterOptions: datastore.FilterOptions{In: []datastore.InQueryOption{
{
Key: "name",
Values: []string{"can@delete"},
},
}}})
Expect(err).ShouldNot(HaveOccurred())
diff = cmp.Diff(len(list), 1)
Expect(diff).Should(BeEmpty())
count, err := kubeStore.Count(context.TODO(), &usr, &datastore.FilterOptions{In: []datastore.InQueryOption{
{
Key: "name",
Values: []string{"can@delete"},
},
}})
Expect(err).ShouldNot(HaveOccurred())
Expect(count).Should(Equal(int64(1)))
usr.Name = "can@delete"
err = kubeStore.Delete(context.TODO(), &usr)
Expect(err).ShouldNot(HaveOccurred())
})
})

View File

@@ -22,6 +22,7 @@ import (
"helm.sh/helm/v3/pkg/repo"
"github.com/getkin/kin-openapi/openapi3"
registryv1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
@@ -1380,3 +1381,26 @@ type ChartRepoResponse struct {
type ChartRepoResponseList struct {
ChartRepoResponse []*ChartRepoResponse `json:"repos"`
}
// ImageInfo the docker image info
type ImageInfo struct {
Name string `json:"name"`
SecretNames []string `json:"secretNames"`
Registry string `json:"registry"`
Message string `json:"message,omitempty"`
Info *registryv1.ConfigFile `json:"info,omitempty"`
Size int64 `json:"size"`
Manifest *registryv1.Manifest `json:"manifest"`
}
// ImageRegistry the image repository info
type ImageRegistry struct {
Name string `json:"name"`
SecretName string `json:"secretName"`
Domain string `json:"domain"`
}
// ListImageRegistryResponse the response struct of listing the image registries
type ListImageRegistryResponse struct {
Registries []ImageRegistry `json:"registries"`
}

View File

@@ -76,7 +76,7 @@ func InitAPIBean() []interface{} {
RegisterAPIInterface(NewTargetAPIInterface())
RegisterAPIInterface(NewVelaQLAPIInterface())
RegisterAPIInterface(NewWebhookAPIInterface())
RegisterAPIInterface(NewHelmAPIInterface())
RegisterAPIInterface(NewRepositoryAPIInterface())
// Authentication
RegisterAPIInterface(NewAuthenticationAPIInterface())

View File

@@ -203,16 +203,6 @@ func (n *projectAPIInterface) GetWebServiceRoute() *restful.WebService {
Returns(400, "Bad Request", bcode.Bcode{}).
Writes([]*apis.Config{}))
ws.Route(ws.GET("/{projectName}/validate_image").To(n.validateImage).
Doc("validate an image in a project").
Metadata(restfulspec.KeyOpenAPITags, tags).
Filter(n.RbacService.CheckPerm("project/image", "get")).
Param(ws.QueryParameter("image", "image name").DataType("string")).
Param(ws.PathParameter("projectName", "identifier of the project").DataType("string")).
Returns(200, "OK", []*apis.ImageResponse{}).
Returns(400, "Bad Request", bcode.Bcode{}).
Writes([]*apis.ImageResponse{}))
ws.Filter(authCheckFilter)
return ws
}
@@ -599,23 +589,3 @@ func (n *projectAPIInterface) getConfigs(req *restful.Request, res *restful.Resp
return
}
}
func (n *projectAPIInterface) validateImage(req *restful.Request, res *restful.Response) {
resp, err := n.ProjectService.ValidateImage(req.Request.Context(), req.PathParameter("projectName"), req.QueryParameter("image"))
if err != nil {
bcode.ReturnError(req, res, err)
return
}
if resp == nil {
if err := res.WriteEntity(apis.EmptyResponse{}); err != nil {
bcode.ReturnError(req, res, err)
return
}
return
}
err = res.WriteEntity(map[string]interface{}{"data": resp})
if err != nil {
bcode.ReturnError(req, res, err)
return
}
}

View File

@@ -17,7 +17,6 @@ limitations under the License.
package api
import (
"context"
"strconv"
restfulspec "github.com/emicklei/go-restful-openapi/v2"
@@ -29,16 +28,18 @@ import (
"github.com/oam-dev/kubevela/pkg/utils"
)
type helmAPIInterface struct {
HelmService service.HelmService `inject:""`
type repositoryAPIInterface struct {
HelmService service.HelmService `inject:""`
ImageService service.ImageService `inject:""`
RbacService service.RBACService `inject:""`
}
// NewHelmAPIInterface will return helm APIInterface
func NewHelmAPIInterface() Interface {
return &helmAPIInterface{}
// NewRepositoryAPIInterface will return the repository APIInterface
func NewRepositoryAPIInterface() Interface {
return &repositoryAPIInterface{}
}
func (h helmAPIInterface) GetWebServiceRoute() *restful.WebService {
func (h repositoryAPIInterface) GetWebServiceRoute() *restful.WebService {
ws := new(restful.WebService)
ws.Path(versionPrefix+"/repository").
Consumes(restful.MIME_XML, restful.MIME_JSON).
@@ -47,11 +48,12 @@ func (h helmAPIInterface) GetWebServiceRoute() *restful.WebService {
tags := []string{"repository", "helm"}
// List charts
// List chart repos
ws.Route(ws.GET("/chart_repos").To(h.listRepo).
Doc("list chart repo").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.QueryParameter("project", "the config project").DataType("string")).
Param(ws.QueryParameter("project", "the config project").DataType("string").Required(true)).
Filter(h.RbacService.CheckPerm("project/config", "list")).
Returns(200, "OK", []string{}).
Returns(400, "Bad Request", bcode.Bcode{}).
Writes([]string{}))
@@ -86,11 +88,31 @@ func (h helmAPIInterface) GetWebServiceRoute() *restful.WebService {
Returns(400, "Bad Request", bcode.Bcode{}).
Writes([]string{}))
ws.Route(ws.GET("/image/repos").To(h.getImageRepos).
Doc("get the oci repos").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.QueryParameter("project", "the config project").DataType("string").Required(true)).
Filter(h.RbacService.CheckPerm("project/config", "list")).
Returns(200, "OK", v1.ListImageRegistryResponse{}).
Returns(400, "Bad Request", bcode.Bcode{}).
Writes([]string{}))
ws.Route(ws.GET("/image/info").To(h.getImageInfo).
Doc("get the oci repos").
Metadata(restfulspec.KeyOpenAPITags, tags).
Param(ws.QueryParameter("project", "the config project").DataType("string").Required(true)).
Param(ws.QueryParameter("name", "the image name").DataType("string").Required(true)).
Param(ws.QueryParameter("secretName", "the secret name of the image repository").DataType("string")).
Filter(h.RbacService.CheckPerm("project/config", "list")).
Returns(200, "OK", v1.ImageInfo{}).
Returns(400, "Bad Request", bcode.Bcode{}).
Writes([]string{}))
ws.Filter(authCheckFilter)
return ws
}
func (h helmAPIInterface) listCharts(req *restful.Request, res *restful.Response) {
func (h repositoryAPIInterface) listCharts(req *restful.Request, res *restful.Response) {
url := utils.Sanitize(req.QueryParameter("repoUrl"))
secName := utils.Sanitize(req.QueryParameter("secretName"))
skipCache, err := isSkipCache(req)
@@ -98,7 +120,7 @@ func (h helmAPIInterface) listCharts(req *restful.Request, res *restful.Response
bcode.ReturnError(req, res, bcode.ErrSkipCacheParameter)
return
}
charts, err := h.HelmService.ListChartNames(context.Background(), url, secName, skipCache)
charts, err := h.HelmService.ListChartNames(req.Request.Context(), url, secName, skipCache)
if err != nil {
bcode.ReturnError(req, res, err)
return
@@ -110,7 +132,7 @@ func (h helmAPIInterface) listCharts(req *restful.Request, res *restful.Response
}
}
func (h helmAPIInterface) listVersions(req *restful.Request, res *restful.Response) {
func (h repositoryAPIInterface) listVersions(req *restful.Request, res *restful.Response) {
url := req.QueryParameter("repoUrl")
chartName := req.PathParameter("chart")
secName := req.QueryParameter("secretName")
@@ -120,7 +142,7 @@ func (h helmAPIInterface) listVersions(req *restful.Request, res *restful.Respon
return
}
versions, err := h.HelmService.ListChartVersions(context.Background(), url, chartName, secName, skipCache)
versions, err := h.HelmService.ListChartVersions(req.Request.Context(), url, chartName, secName, skipCache)
if err != nil {
bcode.ReturnError(req, res, err)
return
@@ -132,7 +154,7 @@ func (h helmAPIInterface) listVersions(req *restful.Request, res *restful.Respon
}
}
func (h helmAPIInterface) chartValues(req *restful.Request, res *restful.Response) {
func (h repositoryAPIInterface) chartValues(req *restful.Request, res *restful.Response) {
url := req.QueryParameter("repoUrl")
secName := req.QueryParameter("secretName")
chartName := req.PathParameter("chart")
@@ -143,7 +165,7 @@ func (h helmAPIInterface) chartValues(req *restful.Request, res *restful.Respons
return
}
versions, err := h.HelmService.GetChartValues(context.Background(), url, chartName, version, secName, skipCache)
versions, err := h.HelmService.GetChartValues(req.Request.Context(), url, chartName, version, secName, skipCache)
if err != nil {
bcode.ReturnError(req, res, err)
return
@@ -155,9 +177,9 @@ func (h helmAPIInterface) chartValues(req *restful.Request, res *restful.Respons
}
}
func (h helmAPIInterface) listRepo(req *restful.Request, res *restful.Response) {
func (h repositoryAPIInterface) listRepo(req *restful.Request, res *restful.Response) {
project := req.QueryParameter("project")
repos, err := h.HelmService.ListChartRepo(context.Background(), project)
repos, err := h.HelmService.ListChartRepo(req.Request.Context(), project)
if err != nil {
bcode.ReturnError(req, res, err)
return
@@ -169,6 +191,31 @@ func (h helmAPIInterface) listRepo(req *restful.Request, res *restful.Response)
}
}
func (h repositoryAPIInterface) getImageRepos(req *restful.Request, res *restful.Response) {
project := req.QueryParameter("project")
repos, err := h.ImageService.ListImageRepos(req.Request.Context(), project)
if err != nil {
bcode.ReturnError(req, res, err)
return
}
err = res.WriteEntity(v1.ListImageRegistryResponse{Registries: repos})
if err != nil {
bcode.ReturnError(req, res, err)
return
}
}
func (h repositoryAPIInterface) getImageInfo(req *restful.Request, res *restful.Response) {
project := req.QueryParameter("project")
imageInfo := h.ImageService.GetImageInfo(req.Request.Context(), project, req.QueryParameter("secretName"), req.QueryParameter("name"))
err := res.WriteEntity(imageInfo)
if err != nil {
bcode.ReturnError(req, res, err)
return
}
}
func isSkipCache(req *restful.Request) (bool, error) {
skipStr := req.QueryParameter("skipCache")
skipCache := false

View File

@@ -264,6 +264,10 @@ func (h *AppHandler) collectHealthStatus(ctx context.Context, wl *appfile.Worklo
var traitStatusList []common.ApplicationTraitStatus
for _, tr := range wl.Traits {
if tr.FullTemplate.TraitDefinition.Spec.ControlPlaneOnly {
namespace = appRev.GetNamespace()
wl.Ctx.SetCtx(context.WithValue(wl.Ctx.GetCtx(), multicluster.ClusterContextKey, multicluster.ClusterLocalName))
}
var traitStatus = common.ApplicationTraitStatus{
Type: tr.Name,
Healthy: true,
@@ -277,6 +281,8 @@ func (h *AppHandler) collectHealthStatus(ctx context.Context, wl *appfile.Worklo
return nil, false, errors.WithMessagef(err, "app=%s, comp=%s, trait=%s, evaluate status message error", appName, wl.Name, tr.Name)
}
traitStatusList = append(traitStatusList, traitStatus)
namespace = appRev.GetNamespace()
wl.Ctx.SetCtx(context.WithValue(wl.Ctx.GetCtx(), multicluster.ClusterContextKey, status.Cluster))
}
status.Traits = traitStatusList

View File

@@ -302,7 +302,7 @@ func strategyUnify(baseFile *ast.File, patchFile *ast.File, params *UnifyParams,
ret := baseInst.Value().Unify(patchInst.Value())
rv, err := toString(ret)
rv, err := toString(ret, removeTmpVar)
if err != nil {
return rv, errors.WithMessage(err, " format result toString")
}

View File

@@ -358,3 +358,38 @@ func listOpen(expr ast.Node) {
}
}
}
func removeTmpVar(expr ast.Node) ast.Node {
switch v := expr.(type) {
case *ast.File:
for _, decl := range v.Decls {
removeTmpVar(decl)
}
case *ast.Field:
removeTmpVar(v.Value)
case *ast.StructLit:
var elts []ast.Decl
for _, elt := range v.Elts {
if field, isField := elt.(*ast.Field); isField {
if ident, isIdent := field.Label.(*ast.Ident); isIdent && strings.HasPrefix(ident.Name, "_") {
continue
}
}
removeTmpVar(elt)
elts = append(elts, elt)
}
v.Elts = elts
case *ast.BinaryExpr:
removeTmpVar(v.X)
removeTmpVar(v.Y)
case *ast.EmbedDecl:
removeTmpVar(v.Expr)
case *ast.Comprehension:
removeTmpVar(v.Value)
case *ast.ListLit:
for _, elt := range v.Elts {
removeTmpVar(elt)
}
}
return expr
}

View File

@@ -23,6 +23,7 @@ import (
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/parser"
"github.com/bmizerany/assert"
"github.com/stretchr/testify/require"
)
func TestWalk(t *testing.T) {
@@ -128,3 +129,33 @@ func TestWalk(t *testing.T) {
}
}
func TestRemoveTmpVar(t *testing.T) {
src := `spec: {
_tmp: "x"
list: [{
_tmp: "x"
retain: "y"
}, {
_tmp: "x"
retain: "z"
}]
retain: "y"
}
`
r := require.New(t)
var runtime cue.Runtime
inst, err := runtime.Compile("-", src)
r.NoError(err)
s, err := toString(inst.Value(), removeTmpVar)
r.NoError(err)
r.Equal(`spec: {
list: [{
retain: "y"
}, {
retain: "z"
}]
retain: "y"
}
`, s)
}

View File

@@ -302,9 +302,6 @@ func (ctx *templateContext) GetCtx() context.Context {
}
func (ctx *templateContext) SetCtx(newContext context.Context) {
if ctx.ctx != nil {
return
}
ctx.ctx = newContext
}

View File

@@ -22,6 +22,9 @@ import (
"fmt"
"github.com/briandowns/spinner"
prismclusterv1alpha1 "github.com/kubevela/prism/pkg/apis/cluster/v1alpha1"
clusterv1alpha1 "github.com/oam-dev/cluster-gateway/pkg/apis/cluster/v1alpha1"
clustercommon "github.com/oam-dev/cluster-gateway/pkg/common"
"github.com/oam-dev/cluster-register/pkg/hub"
"github.com/oam-dev/cluster-register/pkg/spoke"
"github.com/pkg/errors"
@@ -36,11 +39,7 @@ import (
ocmclusterv1 "open-cluster-management.io/api/cluster/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
clusterv1alpha1 "github.com/oam-dev/cluster-gateway/pkg/apis/cluster/v1alpha1"
clustercommon "github.com/oam-dev/cluster-gateway/pkg/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/policy/envbinding"
"github.com/oam-dev/kubevela/pkg/utils"
velaerrors "github.com/oam-dev/kubevela/pkg/utils/errors"
@@ -49,6 +48,7 @@ import (
// KubeClusterConfig info for cluster management
type KubeClusterConfig struct {
FilePath string
ClusterName string
CreateNamespace string
*clientcmdapi.Config
@@ -84,15 +84,26 @@ func (clusterConfig *KubeClusterConfig) Validate() error {
return nil
}
// RegisterByVelaSecret create cluster secrets for KubeVela to use
func (clusterConfig *KubeClusterConfig) RegisterByVelaSecret(ctx context.Context, cli client.Client) error {
if err := ensureClusterNotExists(ctx, cli, clusterConfig.ClusterName); err != nil {
return errors.Wrapf(err, "cannot use cluster name %s", clusterConfig.ClusterName)
// PostRegistration try to create namespace after cluster registered. If failed, cluster will be unregistered.
func (clusterConfig *KubeClusterConfig) PostRegistration(ctx context.Context, cli client.Client) error {
if clusterConfig.CreateNamespace == "" {
return nil
}
if err := ensureNamespaceExists(ctx, cli, clusterConfig.ClusterName, clusterConfig.CreateNamespace); err != nil {
_ = DetachCluster(ctx, cli, clusterConfig.ClusterName, DetachClusterManagedClusterKubeConfigPathOption(clusterConfig.FilePath))
return fmt.Errorf("failed to ensure %s namespace installed in cluster %s: %w", clusterConfig.CreateNamespace, clusterConfig.ClusterName, err)
}
return nil
}
func (clusterConfig *KubeClusterConfig) createClusterSecret(ctx context.Context, cli client.Client, withEndpoint bool) error {
var credentialType clusterv1alpha1.CredentialType
data := map[string][]byte{
"endpoint": []byte(clusterConfig.Cluster.Server),
"ca.crt": clusterConfig.Cluster.CertificateAuthorityData,
data := map[string][]byte{}
if withEndpoint {
data["endpoint"] = []byte(clusterConfig.Cluster.Server)
if !clusterConfig.Cluster.InsecureSkipTLSVerify {
data["ca.crt"] = clusterConfig.Cluster.CertificateAuthorityData
}
}
if len(clusterConfig.AuthInfo.Token) > 0 {
credentialType = clusterv1alpha1.CredentialTypeServiceAccountToken
@@ -113,22 +124,50 @@ func (clusterConfig *KubeClusterConfig) RegisterByVelaSecret(ctx context.Context
Type: corev1.SecretTypeOpaque,
Data: data,
}
if err := cli.Create(ctx, secret); err != nil {
return cli.Create(ctx, secret)
}
// RegisterByVelaSecret create cluster secrets for KubeVela to use
func (clusterConfig *KubeClusterConfig) RegisterByVelaSecret(ctx context.Context, cli client.Client) error {
if err := ensureClusterNotExists(ctx, cli, clusterConfig.ClusterName); err != nil {
return errors.Wrapf(err, "cannot use cluster name %s", clusterConfig.ClusterName)
}
if err := clusterConfig.createClusterSecret(ctx, cli, true); err != nil {
return errors.Wrapf(err, "failed to add cluster to kubernetes")
}
// TODO(somefive): create namespace now only work for cluster secret
if clusterConfig.CreateNamespace != "" {
if err := ensureNamespaceExists(ctx, cli, clusterConfig.ClusterName, clusterConfig.CreateNamespace); err != nil {
_ = cli.Delete(ctx, secret)
return errors.Wrapf(err, "failed to ensure %s namespace installed in cluster %s", clusterConfig.CreateNamespace, clusterConfig.ClusterName)
return clusterConfig.PostRegistration(ctx, cli)
}
// CreateBootstrapConfigMapIfNotExists alternative to
// https://github.com/kubernetes/kubernetes/blob/v1.24.1/cmd/kubeadm/app/phases/bootstraptoken/clusterinfo/clusterinfo.go#L43
func CreateBootstrapConfigMapIfNotExists(ctx context.Context, cli client.Client) error {
cm := &corev1.ConfigMap{}
key := apitypes.NamespacedName{Namespace: metav1.NamespacePublic, Name: "cluster-info"}
if err := cli.Get(ctx, key, cm); err != nil {
if apierrors.IsNotFound(err) {
cm.ObjectMeta = metav1.ObjectMeta{Namespace: key.Namespace, Name: key.Name}
adminConfig, err := clientcmd.NewDefaultPathOptions().GetStartingConfig()
if err != nil {
return err
}
adminCluster := adminConfig.Contexts[adminConfig.CurrentContext].Cluster
bs, err := clientcmd.Write(clientcmdapi.Config{
Clusters: map[string]*clientcmdapi.Cluster{"": adminConfig.Clusters[adminCluster]},
})
if err != nil {
return err
}
cm.Data = map[string]string{"kubeconfig": string(bs)}
return cli.Create(ctx, cm)
}
return err
}
return nil
}
// RegisterClusterManagedByOCM create ocm managed cluster for use
// TODO(somefive): OCM ManagedCluster only support cli join now
func (clusterConfig *KubeClusterConfig) RegisterClusterManagedByOCM(ctx context.Context, args *JoinClusterArgs) error {
func (clusterConfig *KubeClusterConfig) RegisterClusterManagedByOCM(ctx context.Context, cli client.Client, args *JoinClusterArgs) error {
newTrackingSpinner := args.trackingSpinnerFactory
hubCluster, err := hub.NewHubCluster(args.hubConfig)
if err != nil {
@@ -162,6 +201,9 @@ func (clusterConfig *KubeClusterConfig) RegisterClusterManagedByOCM(ctx context.
return errors.Wrap(err, "fail to convert spoke-cluster kubeconfig")
}
if err = CreateBootstrapConfigMapIfNotExists(ctx, cli); err != nil {
return fmt.Errorf("failed to ensure cluster-info ConfigMap in kube-public namespace exists: %w", err)
}
spokeTracker := newTrackingSpinner("Building registration config for the managed cluster")
spokeTracker.FinalMSG = "Successfully prepared registration config.\n"
spokeTracker.Start()
@@ -170,6 +212,7 @@ func (clusterConfig *KubeClusterConfig) RegisterClusterManagedByOCM(ctx context.
args.ioStreams.Infof("Using the api endpoint from hub kubeconfig %q as registration entry.\n", args.hubConfig.Host)
overridingRegistrationEndpoint = args.hubConfig.Host
}
hubKubeToken, err := hubCluster.GenerateHubClusterKubeConfig(ctx, overridingRegistrationEndpoint)
if err != nil {
return errors.Wrap(err, "fail to generate the token for spoke-cluster")
@@ -228,7 +271,7 @@ func (clusterConfig *KubeClusterConfig) RegisterClusterManagedByOCM(ctx context.
// LoadKubeClusterConfigFromFile create KubeClusterConfig from kubeconfig file
func LoadKubeClusterConfigFromFile(filepath string) (*KubeClusterConfig, error) {
clusterConfig := &KubeClusterConfig{}
clusterConfig := &KubeClusterConfig{FilePath: filepath}
var err error
clusterConfig.Config, err = clientcmd.LoadFromFile(filepath)
if err != nil {
@@ -343,7 +386,7 @@ func JoinClusterByKubeConfig(ctx context.Context, cli client.Client, kubeconfigP
return nil, errors.Wrapf(err, "failed to determine the registration endpoint for the hub cluster "+
"when parsing --in-cluster-bootstrap flag")
}
if err = clusterConfig.RegisterClusterManagedByOCM(ctx, args); err != nil {
if err = clusterConfig.RegisterClusterManagedByOCM(ctx, cli, args); err != nil {
return clusterConfig, err
}
}
@@ -382,12 +425,12 @@ func DetachCluster(ctx context.Context, cli client.Client, clusterName string, o
if clusterName == ClusterLocalName {
return ErrReservedLocalClusterName
}
vc, err := GetVirtualCluster(ctx, cli, clusterName)
vc, err := prismclusterv1alpha1.NewClusterClient(cli).Get(ctx, clusterName)
if err != nil {
return err
}
switch vc.Type {
switch vc.Spec.CredentialType {
case clusterv1alpha1.CredentialTypeX509Certificate, clusterv1alpha1.CredentialTypeServiceAccountToken:
clusterSecret, err := getMutableClusterSecret(ctx, cli, clusterName)
if err != nil {
@@ -396,7 +439,7 @@ func DetachCluster(ctx context.Context, cli client.Client, clusterName string, o
if err := cli.Delete(ctx, clusterSecret); err != nil {
return errors.Wrapf(err, "failed to detach cluster %s", clusterName)
}
case types.CredentialTypeOCMManagedCluster:
case prismclusterv1alpha1.CredentialTypeOCMManagedCluster:
if args.managedClusterKubeConfigPath == "" {
return errors.New("kubeconfig-path must be set to detach ocm managed cluster")
}
@@ -414,7 +457,7 @@ func DetachCluster(ctx context.Context, cli client.Client, clusterName string, o
return err
}
managedCluster := ocmclusterv1.ManagedCluster{ObjectMeta: metav1.ObjectMeta{Name: clusterName}}
if err = cli.Delete(context.Background(), &managedCluster); err != nil {
if err = cli.Delete(ctx, &managedCluster); err != nil {
if !apierrors.IsNotFound(err) {
return err
}

View File

@@ -49,6 +49,7 @@ func newDeleteConfig(options ...DeleteOption) *deleteConfig {
// Delete delete resources
func (h *resourceKeeper) Delete(ctx context.Context, manifests []*unstructured.Unstructured, options ...DeleteOption) (err error) {
h.ClearNamespaceForClusterScopedResources(manifests)
if err = h.AdmissionCheck(ctx, manifests); err != nil {
return err
}

View File

@@ -59,6 +59,7 @@ func (h *resourceKeeper) Dispatch(ctx context.Context, manifests []*unstructured
if h.applyOncePolicy != nil && h.applyOncePolicy.Enable && h.applyOncePolicy.Rules == nil {
options = append(options, MetaOnlyOption{})
}
h.ClearNamespaceForClusterScopedResources(manifests)
// 0. check admission
if err = h.AdmissionCheck(ctx, manifests); err != nil {
return err

View File

@@ -0,0 +1,35 @@
/*
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 resourcekeeper
import (
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
// ClearNamespaceForClusterScopedResources clear namespace for cluster scoped resources
func (h *resourceKeeper) ClearNamespaceForClusterScopedResources(manifests []*unstructured.Unstructured) {
for _, manifest := range manifests {
mappings, err := h.Client.RESTMapper().RESTMappings(manifest.GroupVersionKind().GroupKind(), manifest.GroupVersionKind().Version)
if err != nil {
continue
}
if len(mappings) > 0 && mappings[0].Scope.Name() == meta.RESTScopeNameRoot {
manifest.SetNamespace("")
}
}
}

View File

@@ -0,0 +1,55 @@
/*
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 resourcekeeper
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/utils/apply"
)
var _ = Describe("Test ResourceKeeper utilities", func() {
It("Test ClearNamespaceForClusterScopedResources", func() {
cli := testClient
h := &resourceKeeper{
Client: cli,
app: &v1beta1.Application{ObjectMeta: metav1.ObjectMeta{Name: "app", Namespace: "default"}},
applicator: apply.NewAPIApplicator(cli),
cache: newResourceCache(cli),
}
ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "example", Namespace: "vela"}}
nsObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(ns)
Expect(err).Should(Succeed())
cm := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "example", Namespace: "vela"}}
cmObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(cm)
Expect(err).Should(Succeed())
uns := []*unstructured.Unstructured{{Object: nsObj}, {Object: cmObj}}
uns[0].SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("Namespace"))
uns[1].SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("ConfigMap"))
h.ClearNamespaceForClusterScopedResources(uns)
Expect(uns[0].GetNamespace()).Should(Equal(""))
Expect(uns[1].GetNamespace()).Should(Equal("vela"))
})
})

View File

@@ -1,89 +0,0 @@
/*
Copyright 2022 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package image
import (
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/remote"
)
// Meta is the struct for image metadata
type Meta struct {
Registry string
Repository string
Name string
Tag string
}
// DockerHubImageTagResponse is the struct for docker hub image tag response
type DockerHubImageTagResponse struct {
Count int `json:"count"`
Results []Result
}
// Result is the struct for docker hub image tag result
type Result struct {
Name string `json:"name"`
}
// IsExisted checks whether a public or private image exists
func IsExisted(username, password, image string) (bool, error) {
ref, err := name.ParseReference(image)
if err != nil {
return false, err
}
var img v1.Image
if username != "" || password != "" {
basic := &authn.Basic{
Username: username,
Password: password,
}
option := remote.WithAuth(basic)
img, err = remote.Image(ref, option)
if err != nil {
return false, err
}
} else {
img, err = remote.Image(ref)
if err != nil {
return false, err
}
}
_, err = img.Digest()
if err != nil {
return false, err
}
_, err = img.Manifest()
if err != nil {
return false, err
}
return true, nil
}
// RegistryMeta is the struct for registry metadata
type RegistryMeta struct {
Username string `json:"username"`
Password string `json:"password"`
}

View File

@@ -1,135 +0,0 @@
/*
Copyright 2022 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package image
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestExisted(t *testing.T) {
type args struct {
username string
password string
image string
}
type want struct {
existed bool
errMsg string
}
testcases := map[string]struct {
args args
want want
}{
"empty image name": {
args: args{
image: "",
},
want: want{
existed: false,
errMsg: "could not parse referenc",
},
},
"just image name": {
args: args{
image: "nginx",
},
want: want{
existed: true,
},
},
" image name with registry": {
args: args{
image: "docker.io/nginx",
},
want: want{
existed: true,
},
},
"image name with tag": {
args: args{
image: "nginx:latest",
},
want: want{
existed: true,
},
},
"image name with repository": {
args: args{
image: "library/nginx:latest",
},
want: want{
existed: true,
},
},
"image name with registry and repository": {
args: args{
image: "docker.io/library/nginx",
},
want: want{
existed: true,
},
},
"invalid image name": {
args: args{
image: "jfsdfjwfjwf:fwefsfsjflwejfwjfoewfsffsfw",
},
want: want{
existed: false,
errMsg: "UNAUTHORIZED",
},
},
"invalid image registry": {
args: args{
image: "nginx1sf/jfsdfjwfjwf:fwefsfsjflwejfwjfoewfsffsfw",
},
want: want{
existed: false,
errMsg: "UNAUTHORIZED",
},
},
"not docker hub registry": {
args: args{
image: "alibabacloud.com/d/e:v0.1",
},
want: want{
existed: false,
errMsg: "invalid character '<' looking for beginning of value",
},
},
"private registry, invalid authentication": {
args: args{
image: "abcfefsfjflsfjweffwe73rr.com/d/e:v0.1",
username: "admin",
},
want: want{
existed: false,
errMsg: "Get",
},
},
}
for name, tc := range testcases {
t.Run(name, func(t *testing.T) {
got, err := IsExisted(tc.args.username, tc.args.password, tc.args.image)
if err != nil || tc.want.errMsg != "" {
assert.Contains(t, err.Error(), tc.want.errMsg)
}
assert.Equal(t, got, tc.want.existed)
})
}
}

View File

@@ -23,6 +23,7 @@ import (
appsv1 "k8s.io/api/apps/v1"
v12 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
@@ -677,6 +678,10 @@ func iteratorChildResources(ctx context.Context, cluster string, k8sClient clien
clusterCTX := multicluster.ContextWithClusterName(ctx, cluster)
items, err := listItemByRule(clusterCTX, k8sClient, resource, *parentObject, specifiedFunc, rules.DefaultGenListOptionFunc)
if err != nil {
if meta.IsNoMatchError(err) || runtime.IsNotRegisteredError(err) {
log.Logger.Errorf("error to list subresources: %s err: %v", resource.Kind, err)
continue
}
return nil, err
}
for _, item := range items {

View File

@@ -1380,6 +1380,54 @@ var _ = Describe("unit-test to e2e test", func() {
Expect(err).Should(BeNil())
Expect(len(res.List)).Should(Equal(2))
})
It("Test not exist api don't break whole process", func() {
notExistRuleStr := `
- parentResourceType:
group: apps
kind: Deployment
childrenResourceType:
- apiVersion: v2
kind: Pod
`
notExistParentResourceStr := `
- parentResourceType:
group: badgroup
kind: Deployment
childrenResourceType:
- apiVersion: v2
kind: Pod
`
Expect(k8sClient.Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "vela-system"}})).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
badRuleConfigMap := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"},
ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "bad-rule", Labels: map[string]string{oam.LabelResourceRules: "true"}},
Data: map[string]string{relationshipKey: notExistRuleStr},
}
Expect(k8sClient.Create(ctx, &badRuleConfigMap)).Should(BeNil())
notExistParentConfigMap := v1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"},
ObjectMeta: metav1.ObjectMeta{Namespace: types3.DefaultKubeVelaNS, Name: "not-exist-parent", Labels: map[string]string{oam.LabelResourceRules: "true"}},
Data: map[string]string{relationshipKey: notExistParentResourceStr},
}
Expect(k8sClient.Create(ctx, &notExistParentConfigMap)).Should(BeNil())
prd := provider{cli: k8sClient}
opt := `app: {
name: "app"
namespace: "test-namespace"
}`
v, err := value.NewValue(opt, nil, "")
Expect(err).Should(BeNil())
Expect(prd.GetApplicationResourceTree(nil, v, nil)).Should(BeNil())
type Res struct {
List []types.AppliedResource `json:"list"`
}
var res Res
err = v.UnmarshalTo(&res)
Expect(err).Should(BeNil())
Expect(len(res.List)).Should(Equal(2))
})
})
var _ = Describe("test merge globalRules", func() {

View File

@@ -38,9 +38,12 @@ const (
addonGitToken = "gitToken"
addonOssType = "OSS"
addonGitType = "git"
addonGiteeType = "gitee"
addonGitlabType = "gitlab"
addonHelmType = "helm"
addonUsername = "username"
addonPassword = "password"
addonRepoName = "repoName"
)
// NewAddonRegistryCommand return an addon registry command
@@ -223,12 +226,25 @@ func getAddonRegistry(ctx context.Context, c common.Args, name string) error {
return err
}
table := uitable.New()
if registry.OSS != nil {
switch {
case registry.OSS != nil:
table.AddRow("NAME", "Type", "ENDPOINT", "BUCKET", "PATH")
table.AddRow(registry.Name, "OSS", registry.OSS.Endpoint, registry.OSS.Bucket, registry.OSS.Path)
} else {
case registry.Helm != nil:
table.AddRow("NAME", "Type", "ENDPOINT")
table.AddRow(registry.Name, "Helm", registry.Helm.URL)
case registry.Gitee != nil:
table.AddRow("NAME", "Type", "ENDPOINT", "PATH")
table.AddRow(registry.Name, "git", registry.Git.URL, registry.Git.Path)
table.AddRow(registry.Name, "Gitee", registry.Gitee.URL, registry.Gitee.Path)
case registry.Gitlab != nil:
table.AddRow("NAME", "Type", "ENDPOINT", "REPOSITORY", "PATH")
table.AddRow(registry.Name, "Gitlab", registry.Gitlab.URL, registry.Gitlab.Repo, registry.Gitlab.Path)
case registry.Git != nil:
table.AddRow("NAME", "Type", "ENDPOINT", "PATH")
table.AddRow(registry.Name, "Git", registry.Git.URL, registry.Git.Path)
default:
table.AddRow("Name")
table.AddRow(registry.Name)
}
fmt.Println(table.String())
return nil
@@ -331,6 +347,37 @@ func getRegistryFromArgs(cmd *cobra.Command, args []string) (*pkgaddon.Registry,
return nil, err
}
r.Git.Token = token
case addonGiteeType:
r.Gitee = &pkgaddon.GiteeAddonSource{}
r.Gitee.URL = endpoint
path, err := cmd.Flags().GetString(addonPath)
if err != nil {
return nil, err
}
r.Gitee.Path = path
token, err := cmd.Flags().GetString(addonGitToken)
if err != nil {
return nil, err
}
r.Gitee.Token = token
case addonGitlabType:
r.Gitlab = &pkgaddon.GitlabAddonSource{}
r.Gitlab.URL = endpoint
path, err := cmd.Flags().GetString(addonPath)
if err != nil {
return nil, err
}
r.Gitlab.Path = path
token, err := cmd.Flags().GetString(addonGitToken)
if err != nil {
return nil, err
}
r.Gitlab.Token = token
gitLabRepoName, err := cmd.Flags().GetString(addonRepoName)
if err != nil {
return nil, err
}
r.Gitlab.Repo = gitLabRepoName
case addonHelmType:
r.Helm = &pkgaddon.HelmSource{}
r.Helm.URL = endpoint

View File

@@ -24,6 +24,7 @@ import (
"github.com/crossplane/crossplane-runtime/pkg/meta"
"github.com/fatih/color"
prismclusterv1alpha1 "github.com/kubevela/prism/pkg/apis/cluster/v1alpha1"
"github.com/oam-dev/cluster-gateway/pkg/config"
"github.com/oam-dev/cluster-gateway/pkg/generated/clientset/versioned"
"github.com/pkg/errors"
@@ -107,11 +108,11 @@ func NewClusterListCommand(c *common.Args) *cobra.Command {
if err != nil {
return err
}
clusters, err := multicluster.ListVirtualClusters(context.Background(), client)
clusters, err := prismclusterv1alpha1.NewClusterClient(client).List(context.Background())
if err != nil {
return errors.Wrap(err, "fail to get registered cluster")
}
for _, cluster := range clusters {
for _, cluster := range clusters.Items {
var labels []string
for k, v := range cluster.Labels {
if !strings.HasPrefix(k, config.MetaApiGroupName) {
@@ -124,7 +125,7 @@ func NewClusterListCommand(c *common.Args) *cobra.Command {
}
for i, l := range labels {
if i == 0 {
table.AddRow(cluster.Name, cluster.Alias, cluster.Type, cluster.EndPoint, fmt.Sprintf("%v", cluster.Accepted), l)
table.AddRow(cluster.Name, cluster.Spec.Alias, cluster.Spec.CredentialType, cluster.Spec.Endpoint, fmt.Sprintf("%v", cluster.Spec.Accepted), l)
} else {
table.AddRow("", "", "", "", "", l)
}

View File

@@ -226,7 +226,7 @@ func PrintInstalledCompDef(c common2.Args, io cmdutil.IOStreams, filter filterFu
}
table := newUITable()
table.AddRow("NAME", "DEFINITION")
table.AddRow("NAME", "DEFINITION", "DESCRIPTION")
for _, cd := range list.Items {
data, err := json.Marshal(cd)
@@ -242,7 +242,7 @@ func PrintInstalledCompDef(c common2.Args, io cmdutil.IOStreams, filter filterFu
if filter != nil && !filter(capa) {
continue
}
table.AddRow(capa.Name, capa.CrdName)
table.AddRow(capa.Name, capa.CrdName, capa.Description)
}
io.Info(table.String())
return nil

View File

@@ -228,6 +228,7 @@ func PrintInstalledTraitDef(c common2.Args, io cmdutil.IOStreams, filter filterF
table := newUITable()
table.AddRow("NAME", "APPLIES-TO")
table.AddRow("NAME", "APPLIES-TO", "DESCRIPTION")
for _, td := range list.Items {
data, err := json.Marshal(td)
@@ -243,7 +244,7 @@ func PrintInstalledTraitDef(c common2.Args, io cmdutil.IOStreams, filter filterF
if filter != nil && !filter(capa) {
continue
}
table.AddRow(capa.Name, capa.AppliesTo)
table.AddRow(capa.Name, capa.AppliesTo, capa.Description)
}
io.Info(table.String())
return nil

View File

@@ -1,6 +1,7 @@
import (
"encoding/base64"
"encoding/json"
"strconv"
)
"config-image-registry": {
@@ -39,8 +40,8 @@ template: {
if parameter.auth == _|_ {
type: "Opaque"
}
if parameter.auth != _|_ {
stringData: {
stringData: {
if parameter.auth != _|_ && parameter.auth.username != _|_ {
".dockerconfigjson": json.Marshal({
"auths": "\(parameter.registry)": {
"username": parameter.auth.username
@@ -52,11 +53,17 @@ template: {
}
})
}
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
// +usage=Image registry FQDN, such as: index.docker.io
registry: string
// +usage=Authenticate the image registry
auth?: {
@@ -67,5 +74,9 @@ template: {
// +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
}
}