mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-23 14:23:54 +00:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e3ab732df | ||
|
|
62d5507499 | ||
|
|
c0daf688a6 | ||
|
|
48d19a2427 | ||
|
|
4da8d49e60 | ||
|
|
4db9e89816 | ||
|
|
667053409d | ||
|
|
eb9ddaabd3 | ||
|
|
f11a94612f | ||
|
|
56f9d7cb9c | ||
|
|
fbbc666019 | ||
|
|
d0788254cb | ||
|
|
c72a6aef87 | ||
|
|
195b7fe0c7 | ||
|
|
33c9e3b170 | ||
|
|
ea0508a634 | ||
|
|
23e29aa62a | ||
|
|
ed2cb80219 | ||
|
|
1a3d5debd5 | ||
|
|
d4a82fe292 | ||
|
|
963ae400fa | ||
|
|
8f7a8258fe | ||
|
|
70bc306678 | ||
|
|
57428bbc8d | ||
|
|
e08541ca5c | ||
|
|
521a4edc10 | ||
|
|
82b330710c | ||
|
|
4a649f2cf1 | ||
|
|
f6664106a2 | ||
|
|
bbe2a2dec6 | ||
|
|
404c7f6975 | ||
|
|
2edfbabdab | ||
|
|
e7b304de3b | ||
|
|
b8b54baf26 | ||
|
|
87b6c9416e | ||
|
|
cd171d27db | ||
|
|
6d8be8b061 | ||
|
|
e93912acff | ||
|
|
e48e39987f | ||
|
|
6264a66021 | ||
|
|
9191127e01 | ||
|
|
1b047c10ba | ||
|
|
02a1d390c4 | ||
|
|
62866e19d8 | ||
|
|
3dc645ed52 | ||
|
|
e20ef02a6a | ||
|
|
371affb389 | ||
|
|
b35145be82 | ||
|
|
d92c8844ba | ||
|
|
82aaf5098b | ||
|
|
7399666275 | ||
|
|
0b394e766b | ||
|
|
eb386ce9f7 | ||
|
|
e4fa5a5cf1 | ||
|
|
165e011bd0 | ||
|
|
9489b8d511 | ||
|
|
d95942c992 | ||
|
|
c6aa8ddbbc | ||
|
|
c370ef04f3 |
2
.github/workflows/e2e-multicluster-test.yml
vendored
2
.github/workflows/e2e-multicluster-test.yml
vendored
@@ -103,7 +103,7 @@ jobs:
|
||||
run: |
|
||||
make e2e-cleanup
|
||||
make vela-cli
|
||||
make e2e-setup-core
|
||||
make e2e-setup-core-auth
|
||||
make
|
||||
make setup-runtime-e2e-cluster
|
||||
|
||||
|
||||
88
.github/workflows/registry.yml
vendored
88
.github/workflows/registry.yml
vendored
@@ -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,14 +71,70 @@ 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
|
||||
name: Build & Pushing CLI for Dockerhub, GHCR and ACR
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.cli
|
||||
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-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 vela-apiserver for Dockerhub, GHCR and ACR
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.apiserver
|
||||
@@ -97,14 +149,11 @@ jobs:
|
||||
GOPROXY=https://proxy.golang.org
|
||||
tags: |-
|
||||
docker.io/oamdev/vela-apiserver:${{ steps.get_version.outputs.VERSION }}
|
||||
ghcr.io/${{ github.repository }}/vela-apiserver:${{ steps.get_version.outputs.VERSION }}
|
||||
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 }}
|
||||
|
||||
- name: Build & Pushing vela runtime rollout for ACR
|
||||
run: |
|
||||
docker build --build-arg GOPROXY=https://proxy.golang.org --build-arg VERSION=${{ steps.get_version.outputs.VERSION }} --build-arg GITVERSION=git-${{ steps.vars.outputs.git_revision }} -t kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }} .
|
||||
docker push kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }}
|
||||
- uses: docker/build-push-action@v2
|
||||
name: Build & Pushing runtime rollout for Dockerhub and GHCR
|
||||
name: Build & Pushing runtime rollout Dockerhub, GHCR and ACR
|
||||
with:
|
||||
context: .
|
||||
file: runtime/rollout/Dockerfile
|
||||
@@ -119,7 +168,8 @@ jobs:
|
||||
GOPROXY=https://proxy.golang.org
|
||||
tags: |-
|
||||
docker.io/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }}
|
||||
ghcr.io/${{ github.repository }}/vela-rollout:${{ steps.get_version.outputs.VERSION }}
|
||||
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:
|
||||
env:
|
||||
|
||||
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
@@ -121,6 +121,7 @@ jobs:
|
||||
run: ./ossutil --config-file .ossutilconfig sync ./_bin/vela oss://$BUCKET/binary/vela/${{ env.VELA_VERSION }}
|
||||
|
||||
- name: sync the latest version file
|
||||
if: ${{ !contains(env.VELA_VERSION,'alpha') && !contains(env.VELA_VERSION,'beta') }}
|
||||
run: |
|
||||
echo ${{ env.VELA_VERSION }} > ./latest_version
|
||||
./ossutil --config-file .ossutilconfig cp -u ./latest_version oss://$BUCKET/binary/vela/latest_version
|
||||
|
||||
@@ -36,7 +36,7 @@ RUN GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} \
|
||||
# Refer to https://github.com/GoogleContainerTools/distroless for more details
|
||||
# Overwrite `BASE_IMAGE` by passing `--build-arg=BASE_IMAGE=gcr.io/distroless/static:nonroot`
|
||||
FROM ${BASE_IMAGE:-alpine:3.15}
|
||||
# This is required by daemon connnecting with cri
|
||||
# This is required by daemon connecting with cri
|
||||
RUN apk add --no-cache ca-certificates bash expat
|
||||
|
||||
WORKDIR /
|
||||
|
||||
@@ -34,7 +34,7 @@ RUN GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} \
|
||||
# Overwrite `BASE_IMAGE` by passing `--build-arg=BASE_IMAGE=gcr.io/distroless/static:nonroot`
|
||||
|
||||
FROM ${BASE_IMAGE:-alpine:3.15}
|
||||
# This is required by daemon connnecting with cri
|
||||
# This is required by daemon connecting with cri
|
||||
RUN apk add --no-cache ca-certificates bash expat
|
||||
|
||||
WORKDIR /
|
||||
|
||||
43
Dockerfile.cli
Normal file
43
Dockerfile.cli
Normal file
@@ -0,0 +1,43 @@
|
||||
ARG BASE_IMAGE
|
||||
# Build the cli binary
|
||||
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.17-alpine as builder
|
||||
ARG GOPROXY
|
||||
ENV GOPROXY=${GOPROXY:-https://goproxy.cn}
|
||||
WORKDIR /workspace
|
||||
# Copy the Go Modules manifests
|
||||
COPY go.mod go.mod
|
||||
COPY go.sum go.sum
|
||||
# cache deps before building and copying source so that we don't need to re-download as much
|
||||
# and so that source changes don't invalidate our downloaded layer
|
||||
RUN go mod download
|
||||
|
||||
# Copy the go source
|
||||
COPY apis/ apis/
|
||||
COPY pkg/ pkg/
|
||||
COPY version/ version/
|
||||
COPY references/ references/
|
||||
|
||||
# Build
|
||||
ARG TARGETARCH
|
||||
ARG VERSION
|
||||
ARG GITVERSION
|
||||
|
||||
RUN GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH:-amd64} \
|
||||
go build -a -ldflags "-s -w -X github.com/oam-dev/kubevela/version.VelaVersion=${VERSION:-undefined} -X github.com/oam-dev/kubevela/version.GitRevision=${GITVERSION:-undefined}" \
|
||||
-o vela-${TARGETARCH} ./references/cmd/cli/main.go
|
||||
|
||||
|
||||
# Use alpine as base image due to the discussion in issue #1448
|
||||
# You can replace distroless as minimal base image to package the manager binary
|
||||
# Refer to https://github.com/GoogleContainerTools/distroless for more details
|
||||
# Overwrite `BASE_IMAGE` by passing `--build-arg=BASE_IMAGE=gcr.io/distroless/static:nonroot`
|
||||
|
||||
FROM ${BASE_IMAGE:-alpine:3.15}
|
||||
# This is required by daemon connecting with cri
|
||||
RUN apk add --no-cache ca-certificates bash expat
|
||||
|
||||
WORKDIR /
|
||||
|
||||
ARG TARGETARCH
|
||||
COPY --from=builder /workspace/vela-${TARGETARCH} /vela
|
||||
ENTRYPOINT ["/vela"]
|
||||
@@ -39,7 +39,7 @@ RUN GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} \
|
||||
# Overwrite `BASE_IMAGE` by passing `--build-arg=BASE_IMAGE=gcr.io/distroless/static:nonroot`
|
||||
|
||||
FROM ${BASE_IMAGE:-alpine:3.15}
|
||||
# This is required by daemon connnecting with cri
|
||||
# This is required by daemon connecting with cri
|
||||
RUN apk add --no-cache ca-certificates bash expat
|
||||
|
||||
WORKDIR /
|
||||
|
||||
@@ -347,6 +347,8 @@ type WorkflowStep struct {
|
||||
|
||||
SubSteps []WorkflowSubStep `json:"subSteps,omitempty"`
|
||||
|
||||
If string `json:"if,omitempty"`
|
||||
|
||||
DependsOn []string `json:"dependsOn,omitempty"`
|
||||
|
||||
Inputs StepInputs `json:"inputs,omitempty"`
|
||||
@@ -364,6 +366,8 @@ type WorkflowSubStep struct {
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
Properties *runtime.RawExtension `json:"properties,omitempty"`
|
||||
|
||||
If string `json:"if,omitempty"`
|
||||
|
||||
DependsOn []string `json:"dependsOn,omitempty"`
|
||||
|
||||
Inputs StepInputs `json:"inputs,omitempty"`
|
||||
@@ -397,6 +401,8 @@ const (
|
||||
WorkflowStepPhaseSucceeded WorkflowStepPhase = "succeeded"
|
||||
// WorkflowStepPhaseFailed will report error in `message`.
|
||||
WorkflowStepPhaseFailed WorkflowStepPhase = "failed"
|
||||
// WorkflowStepPhaseSkipped will make the controller skip the step.
|
||||
WorkflowStepPhaseSkipped WorkflowStepPhase = "skipped"
|
||||
// WorkflowStepPhaseStopped will make the controller stop the workflow.
|
||||
WorkflowStepPhaseStopped WorkflowStepPhase = "stopped"
|
||||
// WorkflowStepPhaseRunning will make the controller continue the workflow.
|
||||
|
||||
@@ -117,6 +117,9 @@ type PlacementDecision struct {
|
||||
|
||||
// String encode placement decision
|
||||
func (in PlacementDecision) String() string {
|
||||
if in.Namespace == "" {
|
||||
return in.Cluster
|
||||
}
|
||||
return in.Cluster + "/" + in.Namespace
|
||||
}
|
||||
|
||||
|
||||
@@ -169,8 +169,3 @@ const (
|
||||
// VelaCoreConfig is to mark application, config and its secret or Terraform provider lelong to a KubeVela config
|
||||
VelaCoreConfig = "velacore-config"
|
||||
)
|
||||
|
||||
const (
|
||||
// ClusterGatewayAccessorGroup the group to impersonate which allows the access to the cluster-gateway
|
||||
ClusterGatewayAccessorGroup = "cluster-gateway-accessor"
|
||||
)
|
||||
|
||||
@@ -53,11 +53,12 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wai
|
||||
|
||||
### KubeVela workflow parameters
|
||||
|
||||
| Name | Description | Value |
|
||||
| -------------------------------------- | ------------------------------------------------------ | ----- |
|
||||
| `workflow.backoff.maxTime.waitState` | The max backoff time of workflow in a wait condition | `60` |
|
||||
| `workflow.backoff.maxTime.failedState` | The max backoff time of workflow in a failed condition | `300` |
|
||||
| `workflow.step.errorRetryTimes` | The max retry times of a failed workflow step | `10` |
|
||||
| Name | Description | Value |
|
||||
| -------------------------------------- | ------------------------------------------------------ | ------- |
|
||||
| `workflow.enableSuspendOnFailure` | Enable suspend on workflow failure | `false` |
|
||||
| `workflow.backoff.maxTime.waitState` | The max backoff time of workflow in a wait condition | `60` |
|
||||
| `workflow.backoff.maxTime.failedState` | The max backoff time of workflow in a failed condition | `300` |
|
||||
| `workflow.step.errorRetryTimes` | The max retry times of a failed workflow step | `10` |
|
||||
|
||||
|
||||
### KubeVela controller parameters
|
||||
@@ -103,7 +104,7 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wai
|
||||
| `multicluster.clusterGateway.replicaCount` | ClusterGateway replica count | `1` |
|
||||
| `multicluster.clusterGateway.port` | ClusterGateway port | `9443` |
|
||||
| `multicluster.clusterGateway.image.repository` | ClusterGateway image repository | `oamdev/cluster-gateway` |
|
||||
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.3.2` |
|
||||
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.4.0` |
|
||||
| `multicluster.clusterGateway.image.pullPolicy` | ClusterGateway image pull policy | `IfNotPresent` |
|
||||
| `multicluster.clusterGateway.resources.limits.cpu` | ClusterGateway cpu limit | `100m` |
|
||||
| `multicluster.clusterGateway.resources.limits.memory` | ClusterGateway memory limit | `200Mi` |
|
||||
|
||||
@@ -2209,6 +2209,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of
|
||||
WorkflowStep
|
||||
@@ -2253,6 +2255,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input
|
||||
of WorkflowStep
|
||||
@@ -3954,6 +3958,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of WorkflowStep
|
||||
items:
|
||||
@@ -3995,6 +4001,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of
|
||||
WorkflowStep
|
||||
|
||||
@@ -1020,6 +1020,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of WorkflowStep
|
||||
items:
|
||||
@@ -1061,6 +1063,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of
|
||||
WorkflowStep
|
||||
|
||||
@@ -42,6 +42,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of WorkflowStep
|
||||
items:
|
||||
@@ -83,6 +85,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of WorkflowStep
|
||||
items:
|
||||
@@ -147,6 +151,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of WorkflowStep
|
||||
items:
|
||||
@@ -188,6 +194,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of WorkflowStep
|
||||
items:
|
||||
|
||||
@@ -13,7 +13,7 @@ metadata:
|
||||
name: {{ template "kubevela.fullname" . }}-cluster-gateway-tls
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
secretName: {{ template "kubevela.fullname" . }}-cluster-gateway-tls
|
||||
secretName: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-v2
|
||||
duration: 8760h # 1y
|
||||
issuerRef:
|
||||
name: {{ template "kubevela.fullname" . }}-cluster-gateway-issuer
|
||||
|
||||
@@ -31,7 +31,7 @@ spec:
|
||||
- "apiserver"
|
||||
- "--secure-port={{ .Values.multicluster.clusterGateway.port }}"
|
||||
- "--secret-namespace={{ .Release.Namespace }}"
|
||||
- "--feature-gates=APIPriorityAndFairness=false"
|
||||
- "--feature-gates=APIPriorityAndFairness=false,ClientIdentityPenetration={{ .Values.authentication.enabled }}"
|
||||
{{- if .Values.multicluster.clusterGateway.secureTLS.enabled }}
|
||||
- "--tls-cert-file={{ .Values.multicluster.clusterGateway.secureTLS.certPath }}/tls.crt"
|
||||
- "--tls-private-key-file={{ .Values.multicluster.clusterGateway.secureTLS.certPath }}/tls.key"
|
||||
@@ -53,7 +53,7 @@ spec:
|
||||
- name: tls-cert-vol
|
||||
secret:
|
||||
defaultMode: 420
|
||||
secretName: {{ template "kubevela.fullname" . }}-cluster-gateway-tls
|
||||
secretName: {{ template "kubevela.fullname" . }}-cluster-gateway-tls-v2
|
||||
{{ end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
@@ -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
|
||||
@@ -129,7 +129,7 @@ spec:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "kubevela.fullname" . }}:cluster-gateway-access-role
|
||||
name: {{ include "kubevela.fullname" . }}:cluster-gateway:proxy
|
||||
rules:
|
||||
- apiGroups: [ "cluster.core.oam.dev" ]
|
||||
resources: [ "clustergateways/proxy" ]
|
||||
@@ -138,16 +138,16 @@ rules:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ include "kubevela.fullname" . }}:cluster-gateway-access-rolebinding
|
||||
name: {{ include "kubevela.fullname" . }}:cluster-gateway:proxy
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: {{ include "kubevela.fullname" . }}:cluster-gateway-access-role
|
||||
name: {{ include "kubevela.fullname" . }}:cluster-gateway:proxy
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: cluster-gateway-accessor
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
- kind: Group
|
||||
name: kubevela:client
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "kubevela.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{ end }}
|
||||
@@ -86,7 +86,7 @@ spec:
|
||||
- create
|
||||
- --host={{ .Release.Name }}-cluster-gateway-service,{{ .Release.Name }}-cluster-gateway-service.{{ .Release.Namespace }}.svc
|
||||
- --namespace={{ .Release.Namespace }}
|
||||
- --secret-name={{ template "kubevela.fullname" . }}-cluster-gateway-tls
|
||||
- --secret-name={{ template "kubevela.fullname" . }}-cluster-gateway-tls-v2
|
||||
- --cert-name=tls.crt
|
||||
- --key-name=tls.key
|
||||
restartPolicy: OnFailure
|
||||
@@ -131,7 +131,7 @@ spec:
|
||||
- /patch
|
||||
args:
|
||||
- --secret-namespace={{ .Release.Namespace }}
|
||||
- --secret-name={{ template "kubevela.fullname" . }}-cluster-gateway-tls
|
||||
- --secret-name={{ template "kubevela.fullname" . }}-cluster-gateway-tls-v2
|
||||
restartPolicy: OnFailure
|
||||
serviceAccountName: {{ include "kubevela.serviceAccountName" . }}
|
||||
securityContext:
|
||||
|
||||
186
charts/vela-core/templates/defwithtemplate/affinity.yaml
Normal file
186
charts/vela-core/templates/defwithtemplate/affinity.yaml
Normal file
@@ -0,0 +1,186 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/affinity.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: affinity specify affinity and tolerationon K8s pod for your workload which follows the pod spec in path 'spec.template'.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: affinity
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
patch: spec: template: spec: {
|
||||
if parameter.podAffinity != _|_ {
|
||||
affinity: podAffinity: {
|
||||
if parameter.podAffinity.required != _|_ {
|
||||
requiredDuringSchedulingIgnoredDuringExecution: [
|
||||
for k in parameter.podAffinity.required {
|
||||
if k.labelSelector != _|_ {
|
||||
labelSelector: k.labelSelector
|
||||
}
|
||||
if k.namespace != _|_ {
|
||||
namespace: k.namespace
|
||||
}
|
||||
topologyKey: k.topologyKey
|
||||
if k.namespaceSelector != _|_ {
|
||||
namespaceSelector: k.namespaceSelector
|
||||
}
|
||||
}]
|
||||
}
|
||||
if parameter.podAffinity.preferred != _|_ {
|
||||
preferredDuringSchedulingIgnoredDuringExecution: [
|
||||
for k in parameter.podAffinity.preferred {
|
||||
weight: k.weight
|
||||
podAffinityTerm: k.podAffinityTerm
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
if parameter.podAntiAffinity != _|_ {
|
||||
affinity: podAntiAffinity: {
|
||||
if parameter.podAntiAffinity.required != _|_ {
|
||||
requiredDuringSchedulingIgnoredDuringExecution: [
|
||||
for k in parameter.podAntiAffinity.required {
|
||||
if k.labelSelector != _|_ {
|
||||
labelSelector: k.labelSelector
|
||||
}
|
||||
if k.namespace != _|_ {
|
||||
namespace: k.namespace
|
||||
}
|
||||
topologyKey: k.topologyKey
|
||||
if k.namespaceSelector != _|_ {
|
||||
namespaceSelector: k.namespaceSelector
|
||||
}
|
||||
}]
|
||||
}
|
||||
if parameter.podAntiAffinity.preferred != _|_ {
|
||||
preferredDuringSchedulingIgnoredDuringExecution: [
|
||||
for k in parameter.podAntiAffinity.preferred {
|
||||
weight: k.weight
|
||||
podAffinityTerm: k.podAffinityTerm
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
if parameter.nodeAffinity != _|_ {
|
||||
affinity: nodeAffinity: {
|
||||
if parameter.nodeAffinity.required != _|_ {
|
||||
requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: [
|
||||
for k in parameter.nodeAffinity.required.nodeSelectorTerms {
|
||||
if k.matchExpressions != _|_ {
|
||||
matchExpressions: k.matchExpressions
|
||||
}
|
||||
if k.matchFields != _|_ {
|
||||
matchFields: k.matchFields
|
||||
}
|
||||
}]
|
||||
}
|
||||
if parameter.nodeAffinity.preferred != _|_ {
|
||||
preferredDuringSchedulingIgnoredDuringExecution: [
|
||||
for k in parameter.nodeAffinity.preferred {
|
||||
weight: k.weight
|
||||
preference: k.preference
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
if parameter.tolerations != _|_ {
|
||||
tolerations: [
|
||||
for k in parameter.tolerations {
|
||||
if k.key != _|_ {
|
||||
key: k.key
|
||||
}
|
||||
if k.effect != _|_ {
|
||||
effect: k.effect
|
||||
}
|
||||
if k.value != _|_ {
|
||||
value: k.value
|
||||
}
|
||||
operator: k.operator
|
||||
if k.tolerationSeconds != _|_ {
|
||||
tolerationSeconds: k.tolerationSeconds
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
#labelSelector: {
|
||||
matchLabels?: [string]: string
|
||||
matchExpressions?: [...{
|
||||
key: string
|
||||
operator: *"In" | "NotIn" | "Exists" | "DoesNotExist"
|
||||
values?: [...string]
|
||||
}]
|
||||
}
|
||||
#podAffinityTerm: {
|
||||
labelSelector?: #labelSelector
|
||||
namespaces?: [...string]
|
||||
topologyKey: string
|
||||
namespaceSelector?: #labelSelector
|
||||
}
|
||||
#nodeSelecor: {
|
||||
key: string
|
||||
operator: *"In" | "NotIn" | "Exists" | "DoesNotExist" | "Gt" | "Lt"
|
||||
values?: [...string]
|
||||
}
|
||||
#nodeSelectorTerm: {
|
||||
matchExpressions?: [...#nodeSelecor]
|
||||
matchFields?: [...#nodeSelecor]
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Specify the pod affinity scheduling rules
|
||||
podAffinity?: {
|
||||
// +usage=Specify the required during scheduling ignored during execution
|
||||
required?: [...#podAffinityTerm]
|
||||
// +usage=Specify the preferred during scheduling ignored during execution
|
||||
preferred?: [...{
|
||||
// +usage=Specify weight associated with matching the corresponding podAffinityTerm
|
||||
weight: int & >=1 & <=100
|
||||
// +usage=Specify a set of pods
|
||||
podAffinityTerm: #podAffinityTerm
|
||||
}]
|
||||
}
|
||||
// +usage=Specify the pod anti-affinity scheduling rules
|
||||
podAntiAffinity?: {
|
||||
// +usage=Specify the required during scheduling ignored during execution
|
||||
required?: [...#podAffinityTerm]
|
||||
// +usage=Specify the preferred during scheduling ignored during execution
|
||||
preferred?: [...{
|
||||
// +usage=Specify weight associated with matching the corresponding podAffinityTerm
|
||||
weight: int & >=1 & <=100
|
||||
// +usage=Specify a set of pods
|
||||
podAffinityTerm: #podAffinityTerm
|
||||
}]
|
||||
}
|
||||
// +usage=Specify the node affinity scheduling rules for the pod
|
||||
nodeAffinity?: {
|
||||
// +usage=Specify the required during scheduling ignored during execution
|
||||
required?: {
|
||||
// +usage=Specify a list of node selector
|
||||
nodeSelectorTerms: [...#nodeSelectorTerm]
|
||||
}
|
||||
// +usage=Specify the preferred during scheduling ignored during execution
|
||||
preferred?: [...{
|
||||
// +usage=Specify weight associated with matching the corresponding nodeSelector
|
||||
weight: int & >=1 & <=100
|
||||
// +usage=Specify a node selector
|
||||
preference: #nodeSelectorTerm
|
||||
}]
|
||||
}
|
||||
// +usage=Specify tolerant taint
|
||||
tolerations?: [...{
|
||||
key?: string
|
||||
operator: *"Equal" | "Exists"
|
||||
value?: string
|
||||
effect?: "NoSchedule" | "PreferNoSchedule" | "NoExecute"
|
||||
// +usage=Specify the period of time the toleration
|
||||
tolerationSeconds?: int
|
||||
}]
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,6 +5,8 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Set the image of the container.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: container-image
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -5,6 +5,8 @@ kind: WorkflowStepDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Deploy env binding component to target env
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: deploy2env
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -62,7 +62,8 @@ spec:
|
||||
}
|
||||
}
|
||||
}] + [ for k, v in _params.env if _delKeys[k] == _|_ && (_params.replace || _baseEnvMap[k] == _|_) {
|
||||
v
|
||||
name: k
|
||||
value: v
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Patch the output following Json Merge Patch strategy, following RFC 7396.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: json-merge-patch
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -5,6 +5,8 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Patch the output following Json Patch strategy, following RFC 6902.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: json-patch
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/node-affinity.cue
|
||||
# Definition source cue file: vela-templates/definitions/deprecated/node-affinity.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: affinity specify node affinity and toleration on K8s pod for your workload which follows the pod spec in path 'spec.template'.
|
||||
labels:
|
||||
custom.definition.oam.dev/deprecated: "true"
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: node-affinity
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
|
||||
@@ -5,6 +5,8 @@ kind: ComponentDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Ref-objects allow users to specify ref objects to use. Notice that this component type have special handle logic.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: ref-objects
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -5,6 +5,8 @@ kind: WorkflowStepDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: step group
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: step-group
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -20,14 +20,53 @@ metadata:
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: "cluster-admin"
|
||||
name: {{ if .Values.authentication.enabled }} {{ include "kubevela.fullname" . }}:manager {{ else }} "cluster-admin" {{ end }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "kubevela.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
- kind: Group
|
||||
name: core.oam.dev
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
||||
{{ if .Values.authentication.enabled }}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "kubevela.fullname" . }}:manager
|
||||
rules:
|
||||
- apiGroups: ["core.oam.dev", "terraform.core.oam.dev", "prism.oam.dev"]
|
||||
resources: ["*"]
|
||||
verbs: ["*"]
|
||||
- apiGroups: ["cluster.open-cluster-management.io"]
|
||||
resources: ["managedclusters"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: [""]
|
||||
resources: ["users", "groups", "serviceaccounts"]
|
||||
verbs: ["impersonate"]
|
||||
- apiGroups: [""]
|
||||
resources: ["namespaces", "secrets", "services"]
|
||||
verbs: ["get", "watch", "list"]
|
||||
- apiGroups: [""]
|
||||
resources: ["configmaps", "events"]
|
||||
verbs: ["*"]
|
||||
- apiGroups: ["apps"]
|
||||
resources: ["controllerrevisions"]
|
||||
verbs: ["*"]
|
||||
- apiGroups: ["apiregistration.k8s.io"]
|
||||
resources: ["apiservices"]
|
||||
verbs: ["get", "list", "watch", "update"]
|
||||
- apiGroups: ["coordination.k8s.io"]
|
||||
resources: ["leases"]
|
||||
verbs: ["*"]
|
||||
- apiGroups: ["admissionregistration.k8s.io"]
|
||||
resources: ["mutatingwebhookconfigurations", "validatingwebhookconfigurations"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["flowcontrol.apiserver.k8s.io"]
|
||||
resources: ["prioritylevelconfigurations", "flowschemas"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["authorization.k8s.io"]
|
||||
resources: ["subjectaccessreviews"]
|
||||
verbs: ["*"]
|
||||
{{ end }}
|
||||
|
||||
---
|
||||
# permissions to do leader election.
|
||||
@@ -175,6 +214,7 @@ spec:
|
||||
- "--max-workflow-wait-backoff-time={{ .Values.workflow.backoff.maxTime.waitState }}"
|
||||
- "--max-workflow-failed-backoff-time={{ .Values.workflow.backoff.maxTime.failedState }}"
|
||||
- "--max-workflow-step-error-retry-times={{ .Values.workflow.step.errorRetryTimes }}"
|
||||
- "--feature-gates=EnableSuspendOnFailure={{- .Values.workflow.enableSuspendOnFailure | toString -}}"
|
||||
- "--feature-gates=AuthenticateApplication={{- .Values.authentication.enabled | toString -}}"
|
||||
{{ if .Values.authentication.enabled }}
|
||||
{{ if .Values.authentication.withUser }}
|
||||
|
||||
@@ -35,10 +35,12 @@ dependCheckWait: 30s
|
||||
|
||||
## @section KubeVela workflow parameters
|
||||
|
||||
## @param workflow.enableSuspendOnFailure Enable suspend on workflow failure
|
||||
## @param workflow.backoff.maxTime.waitState The max backoff time of workflow in a wait condition
|
||||
## @param workflow.backoff.maxTime.failedState The max backoff time of workflow in a failed condition
|
||||
## @param workflow.step.errorRetryTimes The max retry times of a failed workflow step
|
||||
workflow:
|
||||
enableSuspendOnFailure: false
|
||||
backoff:
|
||||
maxTime:
|
||||
waitState: 60
|
||||
@@ -130,7 +132,7 @@ multicluster:
|
||||
port: 9443
|
||||
image:
|
||||
repository: oamdev/cluster-gateway
|
||||
tag: v1.3.2
|
||||
tag: v1.4.0
|
||||
pullPolicy: IfNotPresent
|
||||
resources:
|
||||
limits:
|
||||
@@ -224,7 +226,7 @@ admissionWebhooks:
|
||||
enabled: true
|
||||
image:
|
||||
repository: oamdev/kube-webhook-certgen
|
||||
tag: v2.4.0
|
||||
tag: v2.4.1
|
||||
pullPolicy: IfNotPresent
|
||||
nodeSelector: {}
|
||||
affinity: {}
|
||||
|
||||
@@ -72,11 +72,12 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-minimal --
|
||||
|
||||
### KubeVela workflow parameters
|
||||
|
||||
| Name | Description | Value |
|
||||
| -------------------------------------- | ------------------------------------------------------ | ----- |
|
||||
| `workflow.backoff.maxTime.waitState` | The max backoff time of workflow in a wait condition | `60` |
|
||||
| `workflow.backoff.maxTime.failedState` | The max backoff time of workflow in a failed condition | `300` |
|
||||
| `workflow.step.errorRetryTimes` | The max retry times of a failed workflow step | `10` |
|
||||
| Name | Description | Value |
|
||||
| -------------------------------------- | ------------------------------------------------------ | ------- |
|
||||
| `workflow.enableSuspendOnFailure` | Enable suspend on workflow failure | `false` |
|
||||
| `workflow.backoff.maxTime.waitState` | The max backoff time of workflow in a wait condition | `60` |
|
||||
| `workflow.backoff.maxTime.failedState` | The max backoff time of workflow in a failed condition | `300` |
|
||||
| `workflow.step.errorRetryTimes` | The max retry times of a failed workflow step | `10` |
|
||||
|
||||
|
||||
### KubeVela controller parameters
|
||||
@@ -105,7 +106,7 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-minimal --
|
||||
| `multicluster.clusterGateway.replicaCount` | ClusterGateway replica count | `1` |
|
||||
| `multicluster.clusterGateway.port` | ClusterGateway port | `9443` |
|
||||
| `multicluster.clusterGateway.image.repository` | ClusterGateway image repository | `oamdev/cluster-gateway` |
|
||||
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.3.2` |
|
||||
| `multicluster.clusterGateway.image.tag` | ClusterGateway image tag | `v1.4.0` |
|
||||
| `multicluster.clusterGateway.image.pullPolicy` | ClusterGateway image pull policy | `IfNotPresent` |
|
||||
| `multicluster.clusterGateway.resources.limits.cpu` | ClusterGateway cpu limit | `100m` |
|
||||
| `multicluster.clusterGateway.resources.limits.memory` | ClusterGateway memory limit | `200Mi` |
|
||||
|
||||
@@ -2209,6 +2209,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of
|
||||
WorkflowStep
|
||||
@@ -2253,6 +2255,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input
|
||||
of WorkflowStep
|
||||
@@ -3954,6 +3958,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of WorkflowStep
|
||||
items:
|
||||
@@ -3995,6 +4001,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of
|
||||
WorkflowStep
|
||||
|
||||
@@ -1020,6 +1020,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of WorkflowStep
|
||||
items:
|
||||
@@ -1061,6 +1063,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of
|
||||
WorkflowStep
|
||||
|
||||
@@ -31,7 +31,7 @@ spec:
|
||||
- "apiserver"
|
||||
- "--secure-port={{ .Values.multicluster.clusterGateway.port }}"
|
||||
- "--secret-namespace={{ .Release.Namespace }}"
|
||||
- "--feature-gates=APIPriorityAndFairness=false"
|
||||
- "--feature-gates=APIPriorityAndFairness=false,ClientIdentityPenetration={{ .Values.authentication.enabled }}"
|
||||
{{ if .Values.multicluster.clusterGateway.secureTLS.enabled }}
|
||||
- "--cert-dir={{ .Values.multicluster.clusterGateway.secureTLS.certPath }}"
|
||||
{{ end }}
|
||||
@@ -194,24 +194,25 @@ spec:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "kubevela.fullname" . }}:cluster-gateway-access-role
|
||||
name: {{ include "kubevela.fullname" . }}:cluster-gateway:proxy
|
||||
rules:
|
||||
- apiGroups: [ "cluster.core.oam.dev" ]
|
||||
resources: [ "clustergateways/proxy" ]
|
||||
verbs: [ "get", "list", "watch", "create", "update", "patch", "delete" ]
|
||||
{{ end }}
|
||||
---
|
||||
{{ if and .Values.multicluster.enabled }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ include "kubevela.fullname" . }}:cluster-gateway-access-rolebinding
|
||||
name: {{ include "kubevela.fullname" . }}:cluster-gateway:proxy
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: {{ include "kubevela.fullname" . }}:cluster-gateway-access-role
|
||||
name: {{ include "kubevela.fullname" . }}:cluster-gateway:proxy
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: cluster-gateway-accessor
|
||||
name: kubevela:client
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "kubevela.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{ end }}
|
||||
186
charts/vela-minimal/templates/defwithtemplate/affinity.yaml
Normal file
186
charts/vela-minimal/templates/defwithtemplate/affinity.yaml
Normal file
@@ -0,0 +1,186 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/affinity.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: affinity specify affinity and tolerationon K8s pod for your workload which follows the pod spec in path 'spec.template'.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: affinity
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
patch: spec: template: spec: {
|
||||
if parameter.podAffinity != _|_ {
|
||||
affinity: podAffinity: {
|
||||
if parameter.podAffinity.required != _|_ {
|
||||
requiredDuringSchedulingIgnoredDuringExecution: [
|
||||
for k in parameter.podAffinity.required {
|
||||
if k.labelSelector != _|_ {
|
||||
labelSelector: k.labelSelector
|
||||
}
|
||||
if k.namespace != _|_ {
|
||||
namespace: k.namespace
|
||||
}
|
||||
topologyKey: k.topologyKey
|
||||
if k.namespaceSelector != _|_ {
|
||||
namespaceSelector: k.namespaceSelector
|
||||
}
|
||||
}]
|
||||
}
|
||||
if parameter.podAffinity.preferred != _|_ {
|
||||
preferredDuringSchedulingIgnoredDuringExecution: [
|
||||
for k in parameter.podAffinity.preferred {
|
||||
weight: k.weight
|
||||
podAffinityTerm: k.podAffinityTerm
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
if parameter.podAntiAffinity != _|_ {
|
||||
affinity: podAntiAffinity: {
|
||||
if parameter.podAntiAffinity.required != _|_ {
|
||||
requiredDuringSchedulingIgnoredDuringExecution: [
|
||||
for k in parameter.podAntiAffinity.required {
|
||||
if k.labelSelector != _|_ {
|
||||
labelSelector: k.labelSelector
|
||||
}
|
||||
if k.namespace != _|_ {
|
||||
namespace: k.namespace
|
||||
}
|
||||
topologyKey: k.topologyKey
|
||||
if k.namespaceSelector != _|_ {
|
||||
namespaceSelector: k.namespaceSelector
|
||||
}
|
||||
}]
|
||||
}
|
||||
if parameter.podAntiAffinity.preferred != _|_ {
|
||||
preferredDuringSchedulingIgnoredDuringExecution: [
|
||||
for k in parameter.podAntiAffinity.preferred {
|
||||
weight: k.weight
|
||||
podAffinityTerm: k.podAffinityTerm
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
if parameter.nodeAffinity != _|_ {
|
||||
affinity: nodeAffinity: {
|
||||
if parameter.nodeAffinity.required != _|_ {
|
||||
requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: [
|
||||
for k in parameter.nodeAffinity.required.nodeSelectorTerms {
|
||||
if k.matchExpressions != _|_ {
|
||||
matchExpressions: k.matchExpressions
|
||||
}
|
||||
if k.matchFields != _|_ {
|
||||
matchFields: k.matchFields
|
||||
}
|
||||
}]
|
||||
}
|
||||
if parameter.nodeAffinity.preferred != _|_ {
|
||||
preferredDuringSchedulingIgnoredDuringExecution: [
|
||||
for k in parameter.nodeAffinity.preferred {
|
||||
weight: k.weight
|
||||
preference: k.preference
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
if parameter.tolerations != _|_ {
|
||||
tolerations: [
|
||||
for k in parameter.tolerations {
|
||||
if k.key != _|_ {
|
||||
key: k.key
|
||||
}
|
||||
if k.effect != _|_ {
|
||||
effect: k.effect
|
||||
}
|
||||
if k.value != _|_ {
|
||||
value: k.value
|
||||
}
|
||||
operator: k.operator
|
||||
if k.tolerationSeconds != _|_ {
|
||||
tolerationSeconds: k.tolerationSeconds
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
#labelSelector: {
|
||||
matchLabels?: [string]: string
|
||||
matchExpressions?: [...{
|
||||
key: string
|
||||
operator: *"In" | "NotIn" | "Exists" | "DoesNotExist"
|
||||
values?: [...string]
|
||||
}]
|
||||
}
|
||||
#podAffinityTerm: {
|
||||
labelSelector?: #labelSelector
|
||||
namespaces?: [...string]
|
||||
topologyKey: string
|
||||
namespaceSelector?: #labelSelector
|
||||
}
|
||||
#nodeSelecor: {
|
||||
key: string
|
||||
operator: *"In" | "NotIn" | "Exists" | "DoesNotExist" | "Gt" | "Lt"
|
||||
values?: [...string]
|
||||
}
|
||||
#nodeSelectorTerm: {
|
||||
matchExpressions?: [...#nodeSelecor]
|
||||
matchFields?: [...#nodeSelecor]
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Specify the pod affinity scheduling rules
|
||||
podAffinity?: {
|
||||
// +usage=Specify the required during scheduling ignored during execution
|
||||
required?: [...#podAffinityTerm]
|
||||
// +usage=Specify the preferred during scheduling ignored during execution
|
||||
preferred?: [...{
|
||||
// +usage=Specify weight associated with matching the corresponding podAffinityTerm
|
||||
weight: int & >=1 & <=100
|
||||
// +usage=Specify a set of pods
|
||||
podAffinityTerm: #podAffinityTerm
|
||||
}]
|
||||
}
|
||||
// +usage=Specify the pod anti-affinity scheduling rules
|
||||
podAntiAffinity?: {
|
||||
// +usage=Specify the required during scheduling ignored during execution
|
||||
required?: [...#podAffinityTerm]
|
||||
// +usage=Specify the preferred during scheduling ignored during execution
|
||||
preferred?: [...{
|
||||
// +usage=Specify weight associated with matching the corresponding podAffinityTerm
|
||||
weight: int & >=1 & <=100
|
||||
// +usage=Specify a set of pods
|
||||
podAffinityTerm: #podAffinityTerm
|
||||
}]
|
||||
}
|
||||
// +usage=Specify the node affinity scheduling rules for the pod
|
||||
nodeAffinity?: {
|
||||
// +usage=Specify the required during scheduling ignored during execution
|
||||
required?: {
|
||||
// +usage=Specify a list of node selector
|
||||
nodeSelectorTerms: [...#nodeSelectorTerm]
|
||||
}
|
||||
// +usage=Specify the preferred during scheduling ignored during execution
|
||||
preferred?: [...{
|
||||
// +usage=Specify weight associated with matching the corresponding nodeSelector
|
||||
weight: int & >=1 & <=100
|
||||
// +usage=Specify a node selector
|
||||
preference: #nodeSelectorTerm
|
||||
}]
|
||||
}
|
||||
// +usage=Specify tolerant taint
|
||||
tolerations?: [...{
|
||||
key?: string
|
||||
operator: *"Equal" | "Exists"
|
||||
value?: string
|
||||
effect?: "NoSchedule" | "PreferNoSchedule" | "NoExecute"
|
||||
// +usage=Specify the period of time the toleration
|
||||
tolerationSeconds?: int
|
||||
}]
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,6 +5,8 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Set the image of the container.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: container-image
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -62,7 +62,8 @@ spec:
|
||||
}
|
||||
}
|
||||
}] + [ for k, v in _params.env if _delKeys[k] == _|_ && (_params.replace || _baseEnvMap[k] == _|_) {
|
||||
v
|
||||
name: k
|
||||
value: v
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Patch the output following Json Merge Patch strategy, following RFC 7396.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: json-merge-patch
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -5,6 +5,8 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Patch the output following Json Patch strategy, following RFC 6902.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: json-patch
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -5,6 +5,8 @@ kind: ComponentDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Ref-objects allow users to specify ref objects to use. Notice that this component type have special handle logic.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: ref-objects
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -5,6 +5,8 @@ kind: WorkflowStepDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: step group
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: step-group
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -15,6 +15,7 @@ metadata:
|
||||
|
||||
---
|
||||
|
||||
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
@@ -22,14 +23,53 @@ metadata:
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: "cluster-admin"
|
||||
name: {{ if .Values.authentication.enabled }} {{ include "kubevela.fullname" . }}:manager {{ else }} "cluster-admin" {{ end }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "kubevela.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
- kind: Group
|
||||
name: core.oam.dev
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
||||
{{ if .Values.authentication.enabled }}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "kubevela.fullname" . }}:manager
|
||||
rules:
|
||||
- apiGroups: ["core.oam.dev", "terraform.core.oam.dev", "prism.oam.dev"]
|
||||
resources: ["*"]
|
||||
verbs: ["*"]
|
||||
- apiGroups: ["cluster.open-cluster-management.io"]
|
||||
resources: ["managedclusters"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: [""]
|
||||
resources: ["users", "groups", "serviceaccounts"]
|
||||
verbs: ["impersonate"]
|
||||
- apiGroups: [""]
|
||||
resources: ["namespaces", "secrets", "services"]
|
||||
verbs: ["get", "watch", "list"]
|
||||
- apiGroups: [""]
|
||||
resources: ["configmaps", "events"]
|
||||
verbs: ["*"]
|
||||
- apiGroups: ["apps"]
|
||||
resources: ["controllerrevisions"]
|
||||
verbs: ["*"]
|
||||
- apiGroups: ["apiregistration.k8s.io"]
|
||||
resources: ["apiservices"]
|
||||
verbs: ["get", "list", "watch", "update"]
|
||||
- apiGroups: ["coordination.k8s.io"]
|
||||
resources: ["leases"]
|
||||
verbs: ["*"]
|
||||
- apiGroups: ["admissionregistration.k8s.io"]
|
||||
resources: ["mutatingwebhookconfigurations", "validatingwebhookconfigurations"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["flowcontrol.apiserver.k8s.io"]
|
||||
resources: ["prioritylevelconfigurations", "flowschemas"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["authorization.k8s.io"]
|
||||
resources: ["subjectaccessreviews"]
|
||||
verbs: ["*"]
|
||||
{{ end }}
|
||||
|
||||
---
|
||||
# permissions to do leader election.
|
||||
@@ -145,6 +185,7 @@ spec:
|
||||
- "--max-workflow-wait-backoff-time={{ .Values.workflow.backoff.maxTime.waitState }}"
|
||||
- "--max-workflow-failed-backoff-time={{ .Values.workflow.backoff.maxTime.failedState }}"
|
||||
- "--max-workflow-step-error-retry-times={{ .Values.workflow.step.errorRetryTimes }}"
|
||||
- "--feature-gates=EnableSuspendOnFailure={{- .Values.workflow.enableSuspendOnFailure | toString -}}"
|
||||
- "--feature-gates=AuthenticateApplication={{- .Values.authentication.enabled | toString -}}"
|
||||
{{ if .Values.authentication.enabled }}
|
||||
{{ if .Values.authentication.withUser }}
|
||||
|
||||
@@ -38,10 +38,12 @@ dependCheckWait: 30s
|
||||
|
||||
## @section KubeVela workflow parameters
|
||||
|
||||
## @param workflow.enableSuspendOnFailure Enable suspend on workflow failure
|
||||
## @param workflow.backoff.maxTime.waitState The max backoff time of workflow in a wait condition
|
||||
## @param workflow.backoff.maxTime.failedState The max backoff time of workflow in a failed condition
|
||||
## @param workflow.step.errorRetryTimes The max retry times of a failed workflow step
|
||||
workflow:
|
||||
enableSuspendOnFailure: false
|
||||
backoff:
|
||||
maxTime:
|
||||
waitState: 60
|
||||
@@ -107,7 +109,7 @@ multicluster:
|
||||
port: 9443
|
||||
image:
|
||||
repository: oamdev/cluster-gateway
|
||||
tag: v1.3.2
|
||||
tag: v1.4.0
|
||||
pullPolicy: IfNotPresent
|
||||
resources:
|
||||
limits:
|
||||
@@ -201,7 +203,7 @@ admissionWebhooks:
|
||||
enabled: true
|
||||
image:
|
||||
repository: oamdev/kube-webhook-certgen
|
||||
tag: v2.4.0
|
||||
tag: v2.4.1
|
||||
pullPolicy: IfNotPresent
|
||||
nodeSelector: {}
|
||||
affinity: {}
|
||||
|
||||
@@ -19,7 +19,6 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
@@ -29,10 +28,12 @@ import (
|
||||
restfulspec "github.com/emicklei/go-restful-openapi/v2"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/google/uuid"
|
||||
flag "github.com/spf13/pflag"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/config"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
"github.com/oam-dev/kubevela/pkg/features"
|
||||
"github.com/oam-dev/kubevela/version"
|
||||
)
|
||||
|
||||
@@ -50,7 +51,7 @@ func main() {
|
||||
flag.BoolVar(&s.serverConfig.DisableStatisticCronJob, "disable-statistic-cronJob", false, "close the system statistic info calculating cronJob")
|
||||
flag.Float64Var(&s.serverConfig.KubeQPS, "kube-api-qps", 100, "the qps for kube clients. Low qps may lead to low throughput. High qps may give stress to api-server.")
|
||||
flag.IntVar(&s.serverConfig.KubeBurst, "kube-api-burst", 300, "the burst for kube clients. Recommend setting it qps*3.")
|
||||
|
||||
features.APIServerMutableFeatureGate.AddFlag(flag.CommandLine)
|
||||
flag.Parse()
|
||||
|
||||
if len(os.Args) > 2 && os.Args[1] == "build-swagger" {
|
||||
@@ -109,19 +110,13 @@ type Server struct {
|
||||
func (s *Server) run(ctx context.Context, errChan chan error) error {
|
||||
log.Logger.Infof("KubeVela information: version: %v, gitRevision: %v", version.VelaVersion, version.GitRevision)
|
||||
|
||||
server, err := apiserver.New(s.serverConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create apiserver failed : %w ", err)
|
||||
}
|
||||
server := apiserver.New(s.serverConfig)
|
||||
|
||||
return server.Run(ctx, errChan)
|
||||
}
|
||||
|
||||
func (s *Server) buildSwagger() (*spec.Swagger, error) {
|
||||
server, err := apiserver.New(s.serverConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
server := apiserver.New(s.serverConfig)
|
||||
config, err := server.BuildRestfulConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -36,7 +36,6 @@ import (
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||||
|
||||
apicommon "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/auth"
|
||||
ctrlClient "github.com/oam-dev/kubevela/pkg/client"
|
||||
@@ -46,13 +45,11 @@ import (
|
||||
oamv1alpha2 "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1alpha2"
|
||||
"github.com/oam-dev/kubevela/pkg/controller/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/packages"
|
||||
"github.com/oam-dev/kubevela/pkg/features"
|
||||
_ "github.com/oam-dev/kubevela/pkg/monitor/metrics"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||
"github.com/oam-dev/kubevela/pkg/resourcekeeper"
|
||||
pkgutils "github.com/oam-dev/kubevela/pkg/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/system"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
@@ -205,18 +202,10 @@ func main() {
|
||||
restConfig.QPS = float32(qps)
|
||||
restConfig.Burst = burst
|
||||
restConfig.Wrap(auth.NewImpersonatingRoundTripper)
|
||||
if utilfeature.DefaultMutableFeatureGate.Enabled(features.ControllerAutoImpersonation) {
|
||||
restConfig.Impersonate.UserName = types.VelaCoreName
|
||||
restConfig.Impersonate.Groups = []string{apicommon.Group}
|
||||
pkgutils.AutoSetSelfImpersonationInConfig(restConfig)
|
||||
}
|
||||
klog.InfoS("Kubernetes Config Loaded",
|
||||
"UserAgent", restConfig.UserAgent,
|
||||
"QPS", restConfig.QPS,
|
||||
"Burst", restConfig.Burst,
|
||||
"Auto-Impersonation", utilfeature.DefaultMutableFeatureGate.Enabled(features.ControllerAutoImpersonation),
|
||||
"Impersonate-User", restConfig.Impersonate.UserName,
|
||||
"Impersonate-Group", strings.Join(restConfig.Impersonate.Groups, ","),
|
||||
)
|
||||
|
||||
// wrapper the round tripper by multi cluster rewriter
|
||||
|
||||
@@ -3910,7 +3910,7 @@
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "identifier of the application ",
|
||||
"description": "identifier of the environment",
|
||||
"name": "envName",
|
||||
"in": "path",
|
||||
"required": true
|
||||
@@ -3950,7 +3950,7 @@
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "identifier of the application ",
|
||||
"description": "identifier of the environment",
|
||||
"name": "envName",
|
||||
"in": "path",
|
||||
"required": true
|
||||
@@ -4013,7 +4013,7 @@
|
||||
"tags": [
|
||||
"rbac"
|
||||
],
|
||||
"summary": "list all project level perm policies",
|
||||
"summary": "list all platform level perm policies",
|
||||
"operationId": "listPlatformPermissions",
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -4026,6 +4026,73 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"consumes": [
|
||||
"application/xml",
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"tags": [
|
||||
"rbac"
|
||||
],
|
||||
"summary": "create the platform perm policy",
|
||||
"operationId": "createPlatformPermission",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v1.CreatePermissionRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v1.PermissionBase"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/permissions/{permissionName}": {
|
||||
"delete": {
|
||||
"consumes": [
|
||||
"application/xml",
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"tags": [
|
||||
"rbac"
|
||||
],
|
||||
"summary": "delete a platform perm policy",
|
||||
"operationId": "deletePlatformPermission",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "identifier of the permission",
|
||||
"name": "permissionName",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/v1.EmptyResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/projects": {
|
||||
@@ -4276,6 +4343,85 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"consumes": [
|
||||
"application/xml",
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"tags": [
|
||||
"project"
|
||||
],
|
||||
"summary": "create a project level perm policy",
|
||||
"operationId": "createProjectPermission",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "identifier of the project",
|
||||
"name": "projectName",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1.PermissionBase"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/projects/{projectName}/permissions/{permissionName}": {
|
||||
"delete": {
|
||||
"consumes": [
|
||||
"application/xml",
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/xml"
|
||||
],
|
||||
"tags": [
|
||||
"project"
|
||||
],
|
||||
"summary": "delete a project level perm policy",
|
||||
"operationId": "deleteProjectPermission",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "identifier of the project",
|
||||
"name": "projectName",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "identifier of the permission",
|
||||
"name": "permissionName",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/v1.PermissionBase"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/projects/{projectName}/roles": {
|
||||
@@ -4990,6 +5136,13 @@
|
||||
"summary": "update platform level role",
|
||||
"operationId": "updatePlatformRole",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "identifier of the role",
|
||||
"name": "roleName",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
@@ -5022,6 +5175,15 @@
|
||||
],
|
||||
"summary": "update platform level role",
|
||||
"operationId": "deletePlatformRole",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "identifier of the role",
|
||||
"name": "roleName",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
@@ -6456,20 +6618,34 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"common.SubStepsStatus": {
|
||||
"common.StepStatus": {
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"mode": {
|
||||
"firstExecuteTime": {
|
||||
"type": "string"
|
||||
},
|
||||
"stepIndex": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"steps": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/common.WorkflowSubStepStatus"
|
||||
}
|
||||
"lastExecuteTime": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"phase": {
|
||||
"type": "string"
|
||||
},
|
||||
"reason": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -6571,7 +6747,45 @@
|
||||
"type": "string"
|
||||
},
|
||||
"subSteps": {
|
||||
"$ref": "#/definitions/common.SubStepsStatus"
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/common.WorkflowSubStepStatus"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"common.WorkflowSubStep": {
|
||||
"required": [
|
||||
"name",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"dependsOn": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"inputs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/common.inputItem"
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"outputs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/common.outputItem"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
@@ -6583,9 +6797,15 @@
|
||||
"id"
|
||||
],
|
||||
"properties": {
|
||||
"firstExecuteTime": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"lastExecuteTime": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -6897,8 +7117,8 @@
|
||||
},
|
||||
"model.Cluster": {
|
||||
"required": [
|
||||
"createTime",
|
||||
"updateTime",
|
||||
"createTime",
|
||||
"name",
|
||||
"alias",
|
||||
"description",
|
||||
@@ -7449,8 +7669,8 @@
|
||||
},
|
||||
"v1.AddonStatusResponse": {
|
||||
"required": [
|
||||
"name",
|
||||
"phase",
|
||||
"name",
|
||||
"args"
|
||||
],
|
||||
"properties": {
|
||||
@@ -7606,12 +7826,12 @@
|
||||
},
|
||||
"v1.ApplicationDeployResponse": {
|
||||
"required": [
|
||||
"status",
|
||||
"note",
|
||||
"envName",
|
||||
"triggerType",
|
||||
"createTime",
|
||||
"version",
|
||||
"status"
|
||||
"envName"
|
||||
],
|
||||
"properties": {
|
||||
"codeInfo": {
|
||||
@@ -8580,6 +8800,38 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.CreatePermissionRequest": {
|
||||
"required": [
|
||||
"name",
|
||||
"alias",
|
||||
"resources",
|
||||
"actions",
|
||||
"effect"
|
||||
],
|
||||
"properties": {
|
||||
"actions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"alias": {
|
||||
"type": "string"
|
||||
},
|
||||
"effect": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"resources": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.CreatePolicyRequest": {
|
||||
"required": [
|
||||
"name",
|
||||
@@ -8776,11 +9028,11 @@
|
||||
},
|
||||
"v1.DetailAddonResponse": {
|
||||
"required": [
|
||||
"name",
|
||||
"version",
|
||||
"description",
|
||||
"icon",
|
||||
"invisible",
|
||||
"name",
|
||||
"description",
|
||||
"version",
|
||||
"icon",
|
||||
"schema",
|
||||
"uiSchema",
|
||||
"definitions",
|
||||
@@ -8860,13 +9112,13 @@
|
||||
},
|
||||
"v1.DetailApplicationResponse": {
|
||||
"required": [
|
||||
"name",
|
||||
"project",
|
||||
"description",
|
||||
"createTime",
|
||||
"icon",
|
||||
"alias",
|
||||
"createTime",
|
||||
"updateTime",
|
||||
"name",
|
||||
"policies",
|
||||
"envBindings",
|
||||
"resourceInfo"
|
||||
@@ -8923,20 +9175,20 @@
|
||||
},
|
||||
"v1.DetailClusterResponse": {
|
||||
"required": [
|
||||
"kubeConfig",
|
||||
"name",
|
||||
"description",
|
||||
"apiServerURL",
|
||||
"createTime",
|
||||
"icon",
|
||||
"status",
|
||||
"reason",
|
||||
"icon",
|
||||
"provider",
|
||||
"kubeConfigSecret",
|
||||
"labels",
|
||||
"dashboardURL",
|
||||
"createTime",
|
||||
"updateTime",
|
||||
"apiServerURL",
|
||||
"alias",
|
||||
"dashboardURL",
|
||||
"updateTime",
|
||||
"labels",
|
||||
"kubeConfig",
|
||||
"kubeConfigSecret",
|
||||
"resourceInfo"
|
||||
],
|
||||
"properties": {
|
||||
@@ -8994,14 +9246,14 @@
|
||||
},
|
||||
"v1.DetailComponentResponse": {
|
||||
"required": [
|
||||
"creator",
|
||||
"appPrimaryKey",
|
||||
"alias",
|
||||
"updateTime",
|
||||
"name",
|
||||
"type",
|
||||
"main",
|
||||
"createTime",
|
||||
"appPrimaryKey",
|
||||
"creator",
|
||||
"updateTime",
|
||||
"name",
|
||||
"definition"
|
||||
],
|
||||
"properties": {
|
||||
@@ -9089,11 +9341,11 @@
|
||||
},
|
||||
"v1.DetailDefinitionResponse": {
|
||||
"required": [
|
||||
"name",
|
||||
"status",
|
||||
"labels",
|
||||
"alias",
|
||||
"description",
|
||||
"status",
|
||||
"labels",
|
||||
"name",
|
||||
"icon",
|
||||
"schema",
|
||||
"uiSchema"
|
||||
@@ -9148,14 +9400,14 @@
|
||||
},
|
||||
"v1.DetailPolicyResponse": {
|
||||
"required": [
|
||||
"creator",
|
||||
"properties",
|
||||
"createTime",
|
||||
"updateTime",
|
||||
"envName",
|
||||
"name",
|
||||
"type",
|
||||
"description"
|
||||
"description",
|
||||
"creator",
|
||||
"properties"
|
||||
],
|
||||
"properties": {
|
||||
"createTime": {
|
||||
@@ -9188,16 +9440,16 @@
|
||||
},
|
||||
"v1.DetailRevisionResponse": {
|
||||
"required": [
|
||||
"updateTime",
|
||||
"note",
|
||||
"triggerType",
|
||||
"reason",
|
||||
"envName",
|
||||
"createTime",
|
||||
"deployUser",
|
||||
"updateTime",
|
||||
"reason",
|
||||
"appPrimaryKey",
|
||||
"version",
|
||||
"status",
|
||||
"envName",
|
||||
"deployUser",
|
||||
"note",
|
||||
"triggerType",
|
||||
"workflowName"
|
||||
],
|
||||
"properties": {
|
||||
@@ -9252,10 +9504,10 @@
|
||||
},
|
||||
"v1.DetailTargetResponse": {
|
||||
"required": [
|
||||
"name",
|
||||
"createTime",
|
||||
"updateTime",
|
||||
"project",
|
||||
"updateTime"
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"alias": {
|
||||
@@ -9295,11 +9547,11 @@
|
||||
},
|
||||
"v1.DetailUserResponse": {
|
||||
"required": [
|
||||
"disabled",
|
||||
"createTime",
|
||||
"lastLoginTime",
|
||||
"name",
|
||||
"email",
|
||||
"disabled",
|
||||
"projects",
|
||||
"roles"
|
||||
],
|
||||
@@ -9340,12 +9592,12 @@
|
||||
},
|
||||
"v1.DetailWorkflowRecordResponse": {
|
||||
"required": [
|
||||
"namespace",
|
||||
"workflowName",
|
||||
"workflowAlias",
|
||||
"applicationRevision",
|
||||
"status",
|
||||
"name",
|
||||
"namespace",
|
||||
"workflowName",
|
||||
"workflowAlias",
|
||||
"deployTime",
|
||||
"deployUser",
|
||||
"note",
|
||||
@@ -9397,14 +9649,14 @@
|
||||
},
|
||||
"v1.DetailWorkflowResponse": {
|
||||
"required": [
|
||||
"createTime",
|
||||
"alias",
|
||||
"description",
|
||||
"enable",
|
||||
"updateTime",
|
||||
"createTime",
|
||||
"name",
|
||||
"default",
|
||||
"envName"
|
||||
"envName",
|
||||
"updateTime",
|
||||
"description"
|
||||
],
|
||||
"properties": {
|
||||
"alias": {
|
||||
@@ -9599,8 +9851,8 @@
|
||||
},
|
||||
"v1.EnvBindingTarget": {
|
||||
"required": [
|
||||
"name",
|
||||
"alias"
|
||||
"alias",
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"alias": {
|
||||
@@ -9983,11 +10235,11 @@
|
||||
},
|
||||
"v1.LoginUserInfoResponse": {
|
||||
"required": [
|
||||
"createTime",
|
||||
"lastLoginTime",
|
||||
"name",
|
||||
"email",
|
||||
"disabled",
|
||||
"createTime",
|
||||
"projects",
|
||||
"platformPermissions",
|
||||
"projectPermissions"
|
||||
@@ -10992,6 +11244,12 @@
|
||||
"properties": {
|
||||
"type": "string"
|
||||
},
|
||||
"subSteps": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/common.WorkflowSubStep"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -11006,22 +11264,6 @@
|
||||
"$ref": "#/definitions/common.Schematic"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1beta2.BaseConfigurationSpec": {
|
||||
"properties": {
|
||||
"customRegion": {
|
||||
"type": "string"
|
||||
},
|
||||
"deleteResource": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"providerRef": {
|
||||
"$ref": "#/definitions/types.Reference"
|
||||
},
|
||||
"writeConnectionSecretToRef": {
|
||||
"$ref": "#/definitions/types.SecretReference"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
# How to garbage collect resources in the order of dependency
|
||||
|
||||
If you want to garbage collect resources in the order of dependency, you can add `order: dependency` in the `garbage-collect` policy.
|
||||
If you want to garbage collect resources in the order of reverse dependency, you can add `order: dependency` in the `garbage-collect` policy.
|
||||
|
||||
> Notice that this order policy is only valid for the resources that are created in the components.
|
||||
|
||||
@@ -8,7 +8,7 @@ In the following example, component `test1` depends on `test2`, and `test2` need
|
||||
|
||||
So the order of deployment is: `test3 -> test2 -> test1`.
|
||||
|
||||
When we add `order: dependency` in `garbage-collect` policy and delete the application, the order of garbage collect is: `test3 -> test2 -> test1`.
|
||||
When we add `order: dependency` in `garbage-collect` policy and delete the application, the order of garbage collect is: `test1 -> test2 -> test3`.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
|
||||
27
docs/examples/traits/affinity/example.yaml
Normal file
27
docs/examples/traits/affinity/example.yaml
Normal file
@@ -0,0 +1,27 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: busybox
|
||||
spec:
|
||||
components:
|
||||
- name: busybox
|
||||
type: webservice
|
||||
properties:
|
||||
image: busybox
|
||||
cmd: ["sleep", "86400"]
|
||||
labels:
|
||||
label-key: label-value
|
||||
to-delete-label-key: to-delete-label-value
|
||||
traits:
|
||||
- type: affinity
|
||||
properties:
|
||||
podAffinity:
|
||||
preferred:
|
||||
- weight: 1
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchExpressions:
|
||||
- key: "secrity"
|
||||
values: ["S1"]
|
||||
namespaces: ["default"]
|
||||
topologyKey: "kubernetes.io/hostname"
|
||||
23
docs/examples/workflow/step-group/README.md
Normal file
23
docs/examples/workflow/step-group/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Step Group
|
||||
|
||||
## How to start
|
||||
|
||||
Edit a yaml file as `example.yaml`, then execute it with `vela up` command.
|
||||
|
||||
## Parameter Introduction
|
||||
|
||||
`step-group` has a `subSteps` parameter which is an array containing any step type whose valid parameters do not include the `step-group` step type itself.
|
||||
|
||||
`step-group` doesn't support `properties` for now.
|
||||
|
||||
## Execute process
|
||||
|
||||
When executing the `step-group` step, the subSteps in the step group are executed in dag mode. The step group will only complete when all subSteps have been executed to completion.
|
||||
SubStep has the same execution behavior as a normal step.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: step-group-example
|
||||
name: example
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
@@ -10,13 +10,22 @@ spec:
|
||||
properties:
|
||||
image: crccheck/hello-world
|
||||
port: 8000
|
||||
- name: express-server2
|
||||
type: webservice
|
||||
properties:
|
||||
image: crccheck/hello-world
|
||||
port: 8000
|
||||
|
||||
workflow:
|
||||
steps:
|
||||
- name: step
|
||||
type: step-group
|
||||
subSteps:
|
||||
- name: apply-server
|
||||
- name: apply-sub-step1
|
||||
type: apply-component
|
||||
properties:
|
||||
component: express-server
|
||||
- name: apply-sub-step2
|
||||
type: apply-component
|
||||
properties:
|
||||
component: express-server2
|
||||
@@ -18,9 +18,13 @@ package e2e
|
||||
|
||||
import (
|
||||
context2 "context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
||||
"github.com/Netflix/go-expect"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/meta"
|
||||
"github.com/onsi/ginkgo"
|
||||
@@ -42,6 +46,7 @@ var (
|
||||
testDeleteJsonAppFile = `{"name":"test-vela-delete","services":{"nginx-test":{"type":"webservice","image":"nginx:1.9.4","port":80}}}`
|
||||
appbasicJsonAppFile = `{"name":"app-basic","services":{"app-basic":{"type":"webservice","image":"nginx:1.9.4","port":80}}}`
|
||||
appbasicAddTraitJsonAppFile = `{"name":"app-basic","services":{"app-basic":{"type":"webservice","image":"nginx:1.9.4","port":80,"scaler":{"replicas":2}}}}`
|
||||
velaQL = "test-component-pod-view{appNs=default,appName=nginx-vela,name=nginx}"
|
||||
)
|
||||
|
||||
var _ = ginkgo.Describe("Test Vela Application", func() {
|
||||
@@ -67,6 +72,9 @@ var _ = ginkgo.Describe("Test Vela Application", func() {
|
||||
|
||||
e2e.JsonAppFileContext("json appfile apply", testDeleteJsonAppFile)
|
||||
ApplicationDeleteWithForceOptions("test delete with force option", "test-vela-delete")
|
||||
|
||||
e2e.JsonAppFileContext("json appfile apply", testDeleteJsonAppFile)
|
||||
VelaQLPodListContext("ql", velaQL)
|
||||
})
|
||||
|
||||
var ApplicationStatusContext = func(context string, applicationName string, workloadType string) bool {
|
||||
@@ -98,7 +106,7 @@ var ApplicationStatusDeeplyContext = func(context string, applicationName, workl
|
||||
cli := fmt.Sprintf("vela status %s", applicationName)
|
||||
output, err := e2e.LongTimeExec(cli, 120*time.Second)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(output).To(gomega.ContainSubstring("healthy"))
|
||||
gomega.Expect(strings.ToLower(output)).To(gomega.ContainSubstring("healthy"))
|
||||
// TODO(zzxwill) need to check workloadType after app status is refined
|
||||
})
|
||||
})
|
||||
@@ -229,3 +237,75 @@ var ApplicationDeleteWithForceOptions = func(context string, appName string) boo
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
type PodList struct {
|
||||
PodList []Pod `form:"podList" json:"podList"`
|
||||
}
|
||||
|
||||
type Pod struct {
|
||||
Status Status `form:"status" json:"status"`
|
||||
Cluster string `form:"cluster" json:"cluster"`
|
||||
Metadata Metadata `form:"metadata" json:"metadata"`
|
||||
Workload Workload `form:"workload" json:"workload"`
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
Phase string `form:"phase" json:"phase"`
|
||||
NodeName string `form:"nodeName" json:"nodeName"`
|
||||
}
|
||||
|
||||
type Metadata struct {
|
||||
Namespace string `form:"namespace" json:"namespace"`
|
||||
}
|
||||
|
||||
type Workload struct {
|
||||
ApiVersion string `form:"apiVersion" json:"apiVersion"`
|
||||
Kind string `form:"kind" json:"kind"`
|
||||
}
|
||||
|
||||
var VelaQLPodListContext = func(context string, velaQL string) bool {
|
||||
return ginkgo.Context(context, func() {
|
||||
ginkgo.It("should get successful result for executing vela ql", func() {
|
||||
args := common.Args{
|
||||
Schema: common.Scheme,
|
||||
}
|
||||
ctx := context2.Background()
|
||||
|
||||
k8sClient, err := args.GetClient()
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
componentView := new(corev1.ConfigMap)
|
||||
gomega.Eventually(func(g gomega.Gomega) {
|
||||
g.Expect(common.ReadYamlToObject("./component-pod-view.yaml", componentView)).Should(gomega.BeNil())
|
||||
g.Expect(k8sClient.Create(ctx, componentView)).Should(gomega.Succeed())
|
||||
}, time.Second*3, time.Millisecond*300).Should(gomega.Succeed())
|
||||
|
||||
cli := fmt.Sprintf("vela ql %s", velaQL)
|
||||
output, err := e2e.Exec(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
var list PodList
|
||||
err = json.Unmarshal([]byte(output), &list)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
for _, v := range list.PodList {
|
||||
if v.Cluster != "" {
|
||||
gomega.Expect(v.Cluster).To(gomega.ContainSubstring("local"))
|
||||
}
|
||||
if v.Status.Phase != "" {
|
||||
gomega.Expect(v.Status.Phase).To(gomega.ContainSubstring("Running"))
|
||||
}
|
||||
if v.Status.NodeName != "" {
|
||||
gomega.Expect(v.Status.NodeName).To(gomega.ContainSubstring("kind-control-plane"))
|
||||
}
|
||||
if v.Metadata.Namespace != "" {
|
||||
gomega.Expect(v.Metadata.Namespace).To(gomega.ContainSubstring("default"))
|
||||
}
|
||||
if v.Workload.ApiVersion != "" {
|
||||
gomega.Expect(v.Workload.ApiVersion).To(gomega.ContainSubstring("apps/v1"))
|
||||
}
|
||||
if v.Workload.Kind != "" {
|
||||
gomega.Expect(v.Workload.Kind).To(gomega.ContainSubstring("Deployment"))
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
98
e2e/application/component-pod-view.yaml
Normal file
98
e2e/application/component-pod-view.yaml
Normal file
@@ -0,0 +1,98 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: test-component-pod-view
|
||||
namespace: vela-system
|
||||
data:
|
||||
template: |
|
||||
import (
|
||||
"vela/ql"
|
||||
"vela/op"
|
||||
)
|
||||
|
||||
parameter: {
|
||||
appName: string
|
||||
appNs: string
|
||||
name?: string
|
||||
cluster?: string
|
||||
clusterNs?: string
|
||||
}
|
||||
|
||||
application: ql.#ListResourcesInApp & {
|
||||
app: {
|
||||
name: parameter.appName
|
||||
namespace: parameter.appNs
|
||||
filter: {
|
||||
if parameter.cluster != _|_ {
|
||||
cluster: parameter.cluster
|
||||
}
|
||||
if parameter.clusterNs != _|_ {
|
||||
clusterNamespace: parameter.clusterNs
|
||||
}
|
||||
if parameter.name != _|_ {
|
||||
components: [parameter.name]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if application.err != _|_ {
|
||||
status: error: application.err
|
||||
}
|
||||
|
||||
if application.err == _|_ {
|
||||
resources: application.list
|
||||
|
||||
podsMap: op.#Steps & {
|
||||
for i, resource in resources {
|
||||
"\(i)": ql.#CollectPods & {
|
||||
value: resource.object
|
||||
cluster: resource.cluster
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
podsWithCluster: [ for i, pods in podsMap for podObj in pods.list {
|
||||
cluster: pods.cluster
|
||||
obj: podObj
|
||||
}]
|
||||
|
||||
podStatus: op.#Steps & {
|
||||
for i, pod in podsWithCluster {
|
||||
"\(i)": op.#Steps & {
|
||||
name: pod.obj.metadata.name
|
||||
containers: {for container in pod.obj.status.containerStatuses {
|
||||
"\(container.name)": {
|
||||
image: container.image
|
||||
state: container.state
|
||||
}
|
||||
}}
|
||||
events: ql.#SearchEvents & {
|
||||
value: pod.obj
|
||||
cluster: pod.cluster
|
||||
}
|
||||
metrics: ql.#Read & {
|
||||
cluster: pod.cluster
|
||||
value: {
|
||||
apiVersion: "metrics.k8s.io/v1beta1"
|
||||
kind: "PodMetrics"
|
||||
metadata: {
|
||||
name: pod.obj.metadata.name
|
||||
namespace: pod.obj.metadata.namespace
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status: {
|
||||
podList: [ for podInfo in podStatus {
|
||||
name: podInfo.name
|
||||
containers: [ for containerName, container in podInfo.containers {
|
||||
containerName
|
||||
}]
|
||||
events: podInfo.events.list
|
||||
}]
|
||||
}
|
||||
}
|
||||
47
go.mod
47
go.mod
@@ -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
|
||||
@@ -25,15 +25,19 @@ require (
|
||||
github.com/emicklei/go-restful-openapi/v2 v2.3.0
|
||||
github.com/emicklei/go-restful/v3 v3.0.0-rc2
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible
|
||||
github.com/fatih/camelcase v1.0.0
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/fluxcd/helm-controller/api v0.21.0
|
||||
github.com/fluxcd/source-controller/api v0.24.4
|
||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible
|
||||
github.com/gertd/go-pluralize v0.1.7
|
||||
github.com/getkin/kin-openapi v0.94.0
|
||||
github.com/go-logr/logr v1.2.0
|
||||
github.com/go-logr/logr v1.2.2
|
||||
github.com/go-openapi/spec v0.19.8
|
||||
github.com/go-playground/validator/v10 v10.9.0
|
||||
github.com/go-resty/resty/v2 v2.7.0
|
||||
github.com/google/go-cmp v0.5.8
|
||||
github.com/google/go-containerregistry v0.9.0
|
||||
github.com/google/go-github/v32 v32.1.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gosuri/uilive v0.0.4
|
||||
@@ -42,10 +46,10 @@ 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 v0.0.0-20220512081342-9b641aa819f3
|
||||
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.3.3-0.20220509095841-4272c540e1e9
|
||||
github.com/oam-dev/cluster-gateway v1.4.0
|
||||
github.com/oam-dev/cluster-register v1.0.4-0.20220325092210-cee4a3d3fb7d
|
||||
github.com/oam-dev/terraform-config-inspect v0.0.0-20210418082552-fc72d929aa28
|
||||
github.com/oam-dev/terraform-controller v0.7.0
|
||||
@@ -56,6 +60,7 @@ require (
|
||||
github.com/openkruise/kruise-api v1.1.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.11.0
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/spf13/cobra v1.4.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
@@ -63,6 +68,7 @@ require (
|
||||
github.com/tidwall/gjson v1.9.3
|
||||
github.com/wercker/stern v0.0.0-20190705090245-4fa46dd6987f
|
||||
github.com/wonderflow/cert-manager-api v1.0.3
|
||||
github.com/xanzy/go-gitlab v0.60.0
|
||||
github.com/xlab/treeprint v1.1.0
|
||||
go.mongodb.org/mongo-driver v1.5.1
|
||||
go.uber.org/zap v1.19.1
|
||||
@@ -70,6 +76,7 @@ require (
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||
golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1
|
||||
@@ -78,7 +85,7 @@ require (
|
||||
helm.sh/helm/v3 v3.7.2
|
||||
istio.io/client-go v0.0.0-20210128182905-ee2edd059e02
|
||||
k8s.io/api v0.23.6
|
||||
k8s.io/apiextensions-apiserver v0.23.5
|
||||
k8s.io/apiextensions-apiserver v0.23.6
|
||||
k8s.io/apimachinery v0.23.6
|
||||
k8s.io/apiserver v0.23.6
|
||||
k8s.io/cli-runtime v0.23.6
|
||||
@@ -98,20 +105,6 @@ require (
|
||||
sigs.k8s.io/yaml v1.3.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fatih/camelcase v1.0.0
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/xanzy/go-gitlab v0.60.0
|
||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0
|
||||
)
|
||||
|
||||
require github.com/google/go-containerregistry v0.9.0
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.6.1 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
@@ -129,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
|
||||
@@ -168,6 +161,9 @@ require (
|
||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
|
||||
github.com/facebookgo/structtag v0.0.0-20150214074306-217e25fb9691 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.1 // indirect
|
||||
github.com/fluxcd/pkg/apis/acl v0.0.3 // indirect
|
||||
github.com/fluxcd/pkg/apis/kustomize v0.3.3 // indirect
|
||||
github.com/fluxcd/pkg/apis/meta v0.13.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/fvbommel/sortorder v1.0.1 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
@@ -187,13 +183,15 @@ require (
|
||||
github.com/golang/snappy v0.0.3 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/gofuzz v1.1.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/googleapis/gnostic v0.5.5 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
@@ -203,6 +201,7 @@ require (
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/klauspost/compress v1.15.4 // indirect
|
||||
github.com/kr/pretty v0.3.0 // indirect
|
||||
github.com/kr/pty v1.1.8 // indirect
|
||||
@@ -255,6 +254,7 @@ require (
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/tjfoc/gmsm v1.3.2 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.0.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.2 // indirect
|
||||
@@ -285,6 +285,7 @@ require (
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect
|
||||
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3 // indirect
|
||||
@@ -301,10 +302,10 @@ require (
|
||||
istio.io/api v0.0.0-20210128181506-0c4b8e54850f // indirect
|
||||
istio.io/gogo-genproto v0.0.0-20190930162913-45029607206a // indirect
|
||||
oras.land/oras-go v0.4.0 // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy v0.0.24 // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy v0.0.30 // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30 // indirect
|
||||
sigs.k8s.io/apiserver-runtime v1.1.1 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.10.1 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
||||
|
||||
49
go.sum
49
go.sum
@@ -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=
|
||||
@@ -668,6 +669,16 @@ github.com/fatih/structtag v1.1.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
|
||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fluxcd/helm-controller/api v0.21.0 h1:MWvVzz6u9jR1aE7j1YaSEjBehw0zMndkODnjAE0/1nQ=
|
||||
github.com/fluxcd/helm-controller/api v0.21.0/go.mod h1:cgP5ZR46HIhC8phUfx4Z60He9zNuIHbH3r8YEVl5ip8=
|
||||
github.com/fluxcd/pkg/apis/acl v0.0.3 h1:Lw0ZHdpnO4G7Zy9KjrzwwBmDZQuy4qEjaU/RvA6k1lc=
|
||||
github.com/fluxcd/pkg/apis/acl v0.0.3/go.mod h1:XPts6lRJ9C9fIF9xVWofmQwftvhY25n1ps7W9xw0XLU=
|
||||
github.com/fluxcd/pkg/apis/kustomize v0.3.3 h1:bPN29SdVzWl0yhgivuf/83IAe2R6vUuDVcB3LzyVU8E=
|
||||
github.com/fluxcd/pkg/apis/kustomize v0.3.3/go.mod h1:5HTOFZfQFVMMqR2rvuxpbZhpb+sQpcTT6RCQZOhjFzA=
|
||||
github.com/fluxcd/pkg/apis/meta v0.13.0 h1:0QuNKEExSjk+Rv0I6a85p2H3xOlWhdxZRsh10waEL/c=
|
||||
github.com/fluxcd/pkg/apis/meta v0.13.0/go.mod h1:Z26X5uTU5LxAyWETGueRQY7TvdPaGfKU7Wye9bdUlho=
|
||||
github.com/fluxcd/source-controller/api v0.24.4 h1:m54sS1rJlgJf5j9qDRgKLhbPJAnJ9dY+VrstPKj0aQo=
|
||||
github.com/fluxcd/source-controller/api v0.24.4/go.mod h1:b0MmMPGE8gcpgSyGXe5m7see77tBW26eZrvGkkPstUs=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
@@ -722,8 +733,9 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
|
||||
github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
|
||||
github.com/go-logr/zapr v1.2.0 h1:n4JnPI1T3Qq1SFEi/F8rwLrZERp2bso19PJZDB9dayk=
|
||||
@@ -1007,8 +1019,9 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17
|
||||
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
|
||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
@@ -1331,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 v0.0.0-20220512081342-9b641aa819f3 h1:SiQjuAJVLa75M/uVufyEylzlmi+1sZzCnsDN76IFTr4=
|
||||
github.com/kubevela/prism v0.0.0-20220512081342-9b641aa819f3/go.mod h1:Ms3P9eWEeddXk7Q51+9sV1cGQL0cjlpBcSdp1/HoCaI=
|
||||
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=
|
||||
@@ -1551,8 +1564,8 @@ github.com/nishanths/predeclared v0.2.1/go.mod h1:HvkGJcA3naj4lOwnFXFDkFxVtSqQMB
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oam-dev/cluster-gateway v1.3.3-0.20220509095841-4272c540e1e9 h1:D3Z+QJi/5+J+wHwVPEo2ygFHXPaMS9t4NHfyIHZatiw=
|
||||
github.com/oam-dev/cluster-gateway v1.3.3-0.20220509095841-4272c540e1e9/go.mod h1:WcxTF3tOZFxRm1wztAJnXPM4cpjYqnEFIuAU9EM6pD0=
|
||||
github.com/oam-dev/cluster-gateway v1.4.0 h1:ZZcNRYsUDRWM5JnNX28/zdSPRKERGstcAY+PaJKA0mE=
|
||||
github.com/oam-dev/cluster-gateway v1.4.0/go.mod h1:qnCczkXtTY7h0SqxjZqAAyKQPwrJjLIFy+IdeoaYKCU=
|
||||
github.com/oam-dev/cluster-register v1.0.4-0.20220325092210-cee4a3d3fb7d h1:ZZsBkksYDzwJEjqx9/XBD+VwlhHz8flkZvMJYzO4ASA=
|
||||
github.com/oam-dev/cluster-register v1.0.4-0.20220325092210-cee4a3d3fb7d/go.mod h1:nKEUMfuEB8pHKsaSah9IA+UQzezrPYebBdRozyNtlZc=
|
||||
github.com/oam-dev/stern v1.13.2 h1:jlGgtJbKmIVhzkH44ft5plkgs8XEfvxbFrQdX60CQR4=
|
||||
@@ -2353,6 +2366,7 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211215060638-4ddde0e984e9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
@@ -2533,6 +2547,7 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -2905,6 +2920,7 @@ google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD
|
||||
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
@@ -3063,8 +3079,9 @@ k8s.io/apiextensions-apiserver v0.21.3/go.mod h1:kl6dap3Gd45+21Jnh6utCx8Z2xxLm8L
|
||||
k8s.io/apiextensions-apiserver v0.22.1/go.mod h1:HeGmorjtRmRLE+Q8dJu6AYRoZccvCMsghwS8XTUYb2c=
|
||||
k8s.io/apiextensions-apiserver v0.22.4/go.mod h1:kH9lxD8dbJ+k0ZizGET55lFgdGjO8t45fgZnCVdZEpw=
|
||||
k8s.io/apiextensions-apiserver v0.23.0/go.mod h1:xIFAEEDlAZgpVBl/1VSjGDmLoXAWRG40+GsWhKhAxY4=
|
||||
k8s.io/apiextensions-apiserver v0.23.5 h1:5SKzdXyvIJKu+zbfPc3kCbWpbxi+O+zdmAJBm26UJqI=
|
||||
k8s.io/apiextensions-apiserver v0.23.5/go.mod h1:ntcPWNXS8ZPKN+zTXuzYMeg731CP0heCTl6gYBxLcuQ=
|
||||
k8s.io/apiextensions-apiserver v0.23.6 h1:v58cQ6Z0/GK1IXYr+oW0fnYl52o9LTY0WgoWvI8uv5Q=
|
||||
k8s.io/apiextensions-apiserver v0.23.6/go.mod h1:YVh17Mphv183THQJA5spNFp9XfoidFyL3WoDgZxQIZU=
|
||||
k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA=
|
||||
k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010/go.mod h1:Waf/xTS2FGRrgXCkO5FP3XxTOWh0qLf2QhL1qFZZ/R8=
|
||||
k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4=
|
||||
@@ -3260,6 +3277,7 @@ k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/
|
||||
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20211208161948-7d6a63dca704/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc=
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
|
||||
@@ -3287,8 +3305,8 @@ rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/apiserver-network-proxy v0.0.24 h1:yaswrAqidc2XdLK2GRacVEBb55g4dg91f/B7b0SYliY=
|
||||
sigs.k8s.io/apiserver-network-proxy v0.0.24/go.mod h1:z/U9KltvRVSMttVl3cdQo8cPuXEjr+Qn3A5sUJR55XI=
|
||||
sigs.k8s.io/apiserver-network-proxy v0.0.30 h1:Zr5Zqd2GymcYUwijHUDEaQ1I3Dx0giTIWaD80N6j2mE=
|
||||
sigs.k8s.io/apiserver-network-proxy v0.0.30/go.mod h1:0wSWl5ohhp7kYl5XOP0w1IZSWTHhe9TojjDGityZxnc=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.24 h1:bCO6TN9VG1bK3nCG5ghQ5httx1HpsG5MD8XtRDySHDM=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.24/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
|
||||
sigs.k8s.io/apiserver-runtime v1.1.0/go.mod h1:cmahVEn9R791yUnSiFMFdwTqi2dOe5WQRNwcY6jb7l0=
|
||||
@@ -3308,8 +3326,9 @@ sigs.k8s.io/controller-tools v0.2.4/go.mod h1:m/ztfQNocGYBgTTCmFdnK94uVvgxeZeE3L
|
||||
sigs.k8s.io/controller-tools v0.2.8/go.mod h1:9VKHPszmf2DHz/QmHkcfZoewO6BL7pPs9uAiBVsaJSE=
|
||||
sigs.k8s.io/controller-tools v0.6.2 h1:+Y8L0UsAugDipGRw8lrkPoAi6XqlQVZuf1DQHME3PgU=
|
||||
sigs.k8s.io/controller-tools v0.6.2/go.mod h1:oaeGpjXn6+ZSEIQkUe/+3I40PNiDYp9aeawbt3xTgJ8=
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s=
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y=
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY=
|
||||
sigs.k8s.io/kind v0.9.0 h1:SoDlXq6pEc7dGagHULNRCCBYrLH6xOi7lqXTRXeAlg4=
|
||||
sigs.k8s.io/kind v0.9.0/go.mod h1:cxKQWwmbtRDzQ+RNKnR6gZG6fjbeTtItp5cGf+ww+1Y=
|
||||
sigs.k8s.io/kube-storage-version-migrator v0.0.4/go.mod h1:mXfSLkx9xbJHQsgNDDUZK/iQTs2tMbx/hsJlWe6Fthw=
|
||||
|
||||
@@ -2209,6 +2209,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of
|
||||
WorkflowStep
|
||||
@@ -2253,6 +2255,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input
|
||||
of WorkflowStep
|
||||
@@ -3954,6 +3958,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of WorkflowStep
|
||||
items:
|
||||
@@ -3995,6 +4001,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of
|
||||
WorkflowStep
|
||||
|
||||
@@ -1021,6 +1021,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of WorkflowStep
|
||||
items:
|
||||
@@ -1062,6 +1064,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of
|
||||
WorkflowStep
|
||||
|
||||
@@ -42,6 +42,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of WorkflowStep
|
||||
items:
|
||||
@@ -83,6 +85,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of WorkflowStep
|
||||
items:
|
||||
@@ -147,6 +151,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of WorkflowStep
|
||||
items:
|
||||
@@ -188,6 +194,8 @@ spec:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
if:
|
||||
type: string
|
||||
inputs:
|
||||
description: StepInputs defines variable input of WorkflowStep
|
||||
items:
|
||||
|
||||
@@ -9,7 +9,7 @@ kubectl-vela:
|
||||
|
||||
# Build the docker image
|
||||
.PHONY: docker-build
|
||||
docker-build: docker-build-core docker-build-apiserver
|
||||
docker-build: docker-build-core docker-build-apiserver docker-build-cli
|
||||
@$(OK)
|
||||
|
||||
.PHONY: docker-build-core
|
||||
@@ -20,6 +20,10 @@ docker-build-core:
|
||||
docker-build-apiserver:
|
||||
docker build --build-arg=VERSION=$(VELA_VERSION) --build-arg=GITVERSION=$(GIT_COMMIT) -t $(VELA_APISERVER_IMAGE) -f Dockerfile.apiserver .
|
||||
|
||||
.PHONY: docker-build-cli
|
||||
docker-build-cli:
|
||||
docker build --build-arg=VERSION=$(VELA_VERSION) --build-arg=GITVERSION=$(GIT_COMMIT) -t $(VELA_CLI_IMAGE) -f Dockerfile.cli .
|
||||
|
||||
# Build the runtime docker image
|
||||
.PHONY: docker-build-runtime-rollout
|
||||
docker-build-runtime-rollout:
|
||||
|
||||
@@ -43,6 +43,7 @@ endif
|
||||
|
||||
# Image URL to use all building/pushing image targets
|
||||
VELA_CORE_IMAGE ?= vela-core:latest
|
||||
VELA_CLI_IMAGE ?= oamdev/vela-cli:latest
|
||||
VELA_CORE_TEST_IMAGE ?= vela-core-test:$(GIT_COMMIT)
|
||||
VELA_APISERVER_IMAGE ?= apiserver:latest
|
||||
VELA_RUNTIME_ROLLOUT_IMAGE ?= vela-runtime-rollout:latest
|
||||
|
||||
@@ -1,14 +1,29 @@
|
||||
|
||||
.PHONY: e2e-setup-core
|
||||
e2e-setup-core:
|
||||
.PHONY: e2e-setup-core-pre-hook
|
||||
e2e-setup-core-pre-hook:
|
||||
sh ./hack/e2e/modify_charts.sh
|
||||
helm upgrade --install --create-namespace --namespace vela-system --set image.pullPolicy=IfNotPresent --set image.repository=vela-core-test --set applicationRevisionLimit=5 --set dependCheckWait=10s --set image.tag=$(GIT_COMMIT) --wait kubevela ./charts/vela-core
|
||||
|
||||
.PHONY: e2e-setup-core-post-hook
|
||||
e2e-setup-core-post-hook:
|
||||
kubectl wait --for=condition=Available deployment/kubevela-vela-core -n vela-system --timeout=180s
|
||||
helm upgrade --install --namespace vela-system --wait oam-rollout --set image.repository=vela-runtime-rollout-test --set image.tag=$(GIT_COMMIT) ./runtime/rollout/charts
|
||||
go run ./e2e/addon/mock &
|
||||
sleep 15
|
||||
bin/vela addon enable rollout
|
||||
|
||||
.PHONY: e2e-setup-core-wo-auth
|
||||
e2e-setup-core-wo-auth:
|
||||
helm upgrade --install --create-namespace --namespace vela-system --set image.pullPolicy=IfNotPresent --set image.repository=vela-core-test --set applicationRevisionLimit=5 --set dependCheckWait=10s --set image.tag=$(GIT_COMMIT) --wait kubevela ./charts/vela-core
|
||||
|
||||
.PHONY: e2e-setup-core-w-auth
|
||||
e2e-setup-core-w-auth:
|
||||
helm upgrade --install --create-namespace --namespace vela-system --set image.pullPolicy=IfNotPresent --set image.repository=vela-core-test --set applicationRevisionLimit=5 --set dependCheckWait=10s --set image.tag=$(GIT_COMMIT) --wait kubevela ./charts/vela-core --set authentication.enabled=true --set authentication.withUser=true --set authentication.groupPattern=*
|
||||
|
||||
.PHONY: e2e-setup-core
|
||||
e2e-setup-core: e2e-setup-core-pre-hook e2e-setup-core-wo-auth e2e-setup-core-post-hook
|
||||
|
||||
.PHONY: e2e-setup-core-auth
|
||||
e2e-setup-core-auth: e2e-setup-core-pre-hook e2e-setup-core-w-auth e2e-setup-core-post-hook
|
||||
|
||||
.PHONY: setup-runtime-e2e-cluster
|
||||
setup-runtime-e2e-cluster:
|
||||
helm upgrade --install --create-namespace --namespace vela-system --kubeconfig=$(RUNTIME_CLUSTER_CONFIG) --set image.pullPolicy=IfNotPresent --set image.repository=vela-runtime-rollout-test --set image.tag=$(GIT_COMMIT) --wait vela-rollout ./runtime/rollout/charts
|
||||
|
||||
@@ -61,6 +61,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
utils2 "github.com/oam-dev/kubevela/pkg/controller/utils"
|
||||
cuemodel "github.com/oam-dev/kubevela/pkg/cue/model"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/model/value"
|
||||
@@ -1418,13 +1419,29 @@ func checkSemVer(actual string, require string) (bool, error) {
|
||||
l := strings.ReplaceAll(require, "v", " ")
|
||||
constraint, err := semver.NewConstraint(l)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to new constraint: %s", err.Error())
|
||||
return false, err
|
||||
}
|
||||
v, err := semver.NewVersion(smeVer)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to new version %s: %s", smeVer, err.Error())
|
||||
return false, err
|
||||
}
|
||||
return constraint.Check(v), nil
|
||||
if constraint.Check(v) {
|
||||
return true, nil
|
||||
}
|
||||
if strings.Contains(actual, "-") && !strings.Contains(require, "-") {
|
||||
smeVer := strings.TrimPrefix(actual[:strings.Index(actual, "-")], "v")
|
||||
v, err := semver.NewVersion(smeVer)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to new version %s: %s", smeVer, err.Error())
|
||||
return false, err
|
||||
}
|
||||
if constraint.Check(v) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func fetchVelaCoreImageTag(ctx context.Context, k8sClient client.Client) (string, error) {
|
||||
|
||||
@@ -763,6 +763,21 @@ func TestCheckSemVer(t *testing.T) {
|
||||
require: ">=v1.3.0-beta.2",
|
||||
res: true,
|
||||
},
|
||||
{
|
||||
actual: "v1.4.0-beta.1",
|
||||
require: ">=v1.3.0",
|
||||
res: true,
|
||||
},
|
||||
{
|
||||
actual: "v1.4.0",
|
||||
require: ">=v1.3.0-beta.2",
|
||||
res: true,
|
||||
},
|
||||
{
|
||||
actual: "1.2.4-beta.2",
|
||||
require: ">=v1.2.4-beta.3",
|
||||
res: false,
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
result, err := checkSemVer(testCase.actual, testCase.require)
|
||||
|
||||
@@ -23,6 +23,9 @@ import (
|
||||
|
||||
"sort"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/helm"
|
||||
@@ -128,19 +131,8 @@ func (i versionedRegistry) loadAddon(ctx context.Context, name, version string)
|
||||
if len(versions) == 0 {
|
||||
return nil, ErrNotExist
|
||||
}
|
||||
var addonVersion *repo.ChartVersion
|
||||
sort.Sort(sort.Reverse(versions))
|
||||
if len(version) == 0 {
|
||||
// if not specify version will always use the latest version
|
||||
addonVersion = versions[0]
|
||||
}
|
||||
var availableVersions []string
|
||||
for i, v := range versions {
|
||||
availableVersions = append(availableVersions, v.Version)
|
||||
if v.Version == version {
|
||||
addonVersion = versions[i]
|
||||
}
|
||||
}
|
||||
addonVersion, availableVersions := chooseVersion(version, versions)
|
||||
if addonVersion == nil {
|
||||
return nil, fmt.Errorf("specified version %s not exist", version)
|
||||
}
|
||||
@@ -191,3 +183,32 @@ func loadAddonPackage(addonName string, files []*loader.BufferedFile) (*WholeAdd
|
||||
APISchema: addonUIData.APISchema,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// chooseVersion will return the target version and all available versions
|
||||
func chooseVersion(specifiedVersion string, versions []*repo.ChartVersion) (*repo.ChartVersion, []string) {
|
||||
var addonVersion *repo.ChartVersion
|
||||
var availableVersions []string
|
||||
for i, v := range versions {
|
||||
availableVersions = append(availableVersions, v.Version)
|
||||
if addonVersion != nil {
|
||||
// already find the latest not-prerelease version, skip the find
|
||||
continue
|
||||
}
|
||||
if len(specifiedVersion) != 0 {
|
||||
if v.Version == specifiedVersion {
|
||||
addonVersion = versions[i]
|
||||
}
|
||||
} else {
|
||||
vv, err := semver.NewVersion(v.Version)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if len(vv.Prerelease()) != 0 {
|
||||
continue
|
||||
}
|
||||
addonVersion = v
|
||||
log.Logger.Infof("Not specified any version, so use the latest version %s", v.Version)
|
||||
}
|
||||
}
|
||||
return addonVersion, availableVersions
|
||||
}
|
||||
|
||||
@@ -27,6 +27,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/repo"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -98,6 +101,33 @@ func TestVersionRegistry(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestChooseAddonVersion(t *testing.T) {
|
||||
versions := []*repo.ChartVersion{
|
||||
{
|
||||
Metadata: &chart.Metadata{
|
||||
Version: "v1.4.0-beta1",
|
||||
},
|
||||
},
|
||||
{
|
||||
Metadata: &chart.Metadata{
|
||||
Version: "v1.3.6",
|
||||
},
|
||||
},
|
||||
{
|
||||
Metadata: &chart.Metadata{
|
||||
Version: "v1.2.0",
|
||||
},
|
||||
},
|
||||
}
|
||||
targetVersion, availableVersion := chooseVersion("v1.2.0", versions)
|
||||
assert.Equal(t, availableVersion, []string{"v1.4.0-beta1", "v1.3.6", "v1.2.0"})
|
||||
assert.Equal(t, targetVersion.Version, "v1.2.0")
|
||||
|
||||
targetVersion, availableVersion = chooseVersion("", versions)
|
||||
assert.Equal(t, availableVersion, []string{"v1.4.0-beta1", "v1.3.6", "v1.2.0"})
|
||||
assert.Equal(t, targetVersion.Version, "v1.3.6")
|
||||
}
|
||||
|
||||
var versionedHandler http.HandlerFunc = func(writer http.ResponseWriter, request *http.Request) {
|
||||
switch {
|
||||
case strings.Contains(request.URL.Path, "index.yaml"):
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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
|
||||
|
||||
97
pkg/apiserver/domain/repository/application.go
Normal file
97
pkg/apiserver/domain/repository/application.go
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
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 repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/infrastructure/datastore"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
)
|
||||
|
||||
// ListApplicationPolicies query the application policies
|
||||
func ListApplicationPolicies(ctx context.Context, store datastore.DataStore, app *model.Application) (list []*model.ApplicationPolicy, err error) {
|
||||
var policy = model.ApplicationPolicy{
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
}
|
||||
policies, err := store.List(ctx, &policy, &datastore.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, policy := range policies {
|
||||
pm := policy.(*model.ApplicationPolicy)
|
||||
list = append(list, pm)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ListApplicationEnvPolicies list the policies that only belong to the specified env
|
||||
func ListApplicationEnvPolicies(ctx context.Context, store datastore.DataStore, app *model.Application, envName string) (list []*model.ApplicationPolicy, err error) {
|
||||
var policy = model.ApplicationPolicy{
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
EnvName: envName,
|
||||
}
|
||||
policies, err := store.List(ctx, &policy, &datastore.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, policy := range policies {
|
||||
pm := policy.(*model.ApplicationPolicy)
|
||||
list = append(list, pm)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ListApplicationCommonPolicies list the policies that common to all environments
|
||||
func ListApplicationCommonPolicies(ctx context.Context, store datastore.DataStore, app *model.Application) (list []*model.ApplicationPolicy, err error) {
|
||||
var policy = model.ApplicationPolicy{
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
}
|
||||
policies, err := store.List(ctx, &policy, &datastore.ListOptions{
|
||||
FilterOptions: datastore.FilterOptions{
|
||||
IsNotExist: []datastore.IsNotExistQueryOption{{
|
||||
Key: "envName",
|
||||
}},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, policy := range policies {
|
||||
pm := policy.(*model.ApplicationPolicy)
|
||||
list = append(list, pm)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteApplicationEnvPolicies delete the policies via app name and env name
|
||||
func DeleteApplicationEnvPolicies(ctx context.Context, store datastore.DataStore, app *model.Application, envName string) error {
|
||||
log.Logger.Debugf("clear the policies via app name %s and env name %s", app.PrimaryKey(), envName)
|
||||
policies, err := ListApplicationEnvPolicies(ctx, store, app, envName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, policy := range policies {
|
||||
if err := store.Delete(ctx, policy); err != nil && !errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
log.Logger.Errorf("fail to clear the policies belong to the env %w", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
54
pkg/apiserver/domain/repository/grpc.go
Normal file
54
pkg/apiserver/domain/repository/grpc.go
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
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 repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/infrastructure/datastore"
|
||||
)
|
||||
|
||||
// ListRoles list roles from store
|
||||
func ListRoles(ctx context.Context, store datastore.DataStore, projectName string, page, pageSize int) ([]*model.Role, int64, error) {
|
||||
var role = model.Role{
|
||||
Project: projectName,
|
||||
}
|
||||
var filter datastore.FilterOptions
|
||||
if projectName == "" {
|
||||
filter.IsNotExist = append(filter.IsNotExist, datastore.IsNotExistQueryOption{
|
||||
Key: "project",
|
||||
})
|
||||
}
|
||||
entities, err := store.List(ctx, &role, &datastore.ListOptions{FilterOptions: filter, Page: page, PageSize: pageSize, SortBy: []datastore.SortOption{{Key: "createTime", Order: datastore.SortOrderDescending}}})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
var roles []*model.Role
|
||||
for i := range entities {
|
||||
roles = append(roles, entities[i].(*model.Role))
|
||||
}
|
||||
count := int64(len(roles))
|
||||
if page > 0 && pageSize > 0 {
|
||||
var err error
|
||||
count, err = store.Count(ctx, &role, &filter)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
}
|
||||
return roles, count, nil
|
||||
}
|
||||
@@ -457,13 +457,13 @@ func HaveTerraformWorkload(ctx context.Context, kubeClient client.Client, compon
|
||||
return terraformComponents
|
||||
}
|
||||
|
||||
func createOverriteConfigForTerraformComponent(env *model.Env, target *model.Target, terraformComponents []*model.ApplicationComponent) v1alpha1.EnvConfig {
|
||||
func createOverrideConfigForTerraformComponent(env *model.Env, target *model.Target, terraformComponents []*model.ApplicationComponent) v1alpha1.EnvConfig {
|
||||
placement := v1alpha1.EnvPlacement{}
|
||||
if target.Cluster != nil {
|
||||
placement.ClusterSelector = &common.ClusterSelector{Name: target.Cluster.ClusterName}
|
||||
placement.NamespaceSelector = &v1alpha1.NamespaceSelector{Name: target.Cluster.Namespace}
|
||||
}
|
||||
var componentPatchs []v1alpha1.EnvComponentPatch
|
||||
var componentPatches []v1alpha1.EnvComponentPatch
|
||||
// init cloud application region and provider info
|
||||
for _, component := range terraformComponents {
|
||||
properties := model.JSONStruct{
|
||||
@@ -476,7 +476,7 @@ func createOverriteConfigForTerraformComponent(env *model.Env, target *model.Tar
|
||||
},
|
||||
}
|
||||
if region, ok := target.Variable["region"]; ok {
|
||||
properties["region"] = region
|
||||
properties["customRegion"] = region
|
||||
}
|
||||
if providerName, ok := target.Variable["providerName"]; ok {
|
||||
properties["providerRef"].(map[string]interface{})["name"] = providerName
|
||||
@@ -484,7 +484,7 @@ func createOverriteConfigForTerraformComponent(env *model.Env, target *model.Tar
|
||||
if providerNamespace, ok := target.Variable["providerNamespace"]; ok {
|
||||
properties["providerRef"].(map[string]interface{})["namespace"] = providerNamespace
|
||||
}
|
||||
componentPatchs = append(componentPatchs, v1alpha1.EnvComponentPatch{
|
||||
componentPatches = append(componentPatches, v1alpha1.EnvComponentPatch{
|
||||
Name: component.Name,
|
||||
Properties: properties.RawExtension(),
|
||||
Type: component.Type,
|
||||
@@ -495,7 +495,7 @@ func createOverriteConfigForTerraformComponent(env *model.Env, target *model.Tar
|
||||
Name: genPolicyEnvName(target.Name),
|
||||
Placement: placement,
|
||||
Patch: v1alpha1.EnvPatch{
|
||||
Components: componentPatchs,
|
||||
Components: componentPatches,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -543,7 +543,7 @@ func GenEnvWorkflowStepsAndPolicies(ctx context.Context, kubeClient client.Clien
|
||||
}),
|
||||
}
|
||||
workflowSteps = append(workflowSteps, step)
|
||||
envs = append(envs, createOverriteConfigForTerraformComponent(env, target, terraformComponents))
|
||||
envs = append(envs, createOverrideConfigForTerraformComponent(env, target, terraformComponents))
|
||||
}
|
||||
properties, err := model.NewJSONStructByStruct(v1alpha1.EnvBindingSpec{
|
||||
Envs: envs,
|
||||
|
||||
@@ -244,7 +244,7 @@ func (c *applicationServiceImpl) DetailApplication(ctx context.Context, app *mod
|
||||
}
|
||||
}
|
||||
base := assembler.ConvertAppModelToBase(app, []*apisv1.ProjectBase{project})
|
||||
policies, err := c.queryApplicationPolicies(ctx, app)
|
||||
policies, err := repository.ListApplicationPolicies(ctx, c.Store, app)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -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,
|
||||
@@ -589,7 +589,7 @@ func (c *applicationServiceImpl) DetailComponent(ctx context.Context, app *model
|
||||
|
||||
// ListPolicies list application policies
|
||||
func (c *applicationServiceImpl) ListPolicies(ctx context.Context, app *model.Application) ([]*apisv1.PolicyBase, error) {
|
||||
policies, err := c.queryApplicationPolicies(ctx, app)
|
||||
policies, err := repository.ListApplicationPolicies(ctx, c.Store, app)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -600,21 +600,6 @@ func (c *applicationServiceImpl) ListPolicies(ctx context.Context, app *model.Ap
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (c *applicationServiceImpl) queryApplicationPolicies(ctx context.Context, app *model.Application) (list []*model.ApplicationPolicy, err error) {
|
||||
var policy = model.ApplicationPolicy{
|
||||
AppPrimaryKey: app.PrimaryKey(),
|
||||
}
|
||||
policies, err := c.Store.List(ctx, &policy, &datastore.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, policy := range policies {
|
||||
pm := policy.(*model.ApplicationPolicy)
|
||||
list = append(list, pm)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DetailPolicy detail app policy
|
||||
// TODO: Add status data about the policy.
|
||||
func (c *applicationServiceImpl) DetailPolicy(ctx context.Context, app *model.Application, policyName string) (*apisv1.DetailPolicyResponse, error) {
|
||||
@@ -853,22 +838,11 @@ func (c *applicationServiceImpl) renderOAMApplication(ctx context.Context, appMo
|
||||
}
|
||||
|
||||
// query the policies for this environment
|
||||
var policy = model.ApplicationPolicy{
|
||||
AppPrimaryKey: appModel.PrimaryKey(),
|
||||
}
|
||||
policies, err := c.Store.List(ctx, &policy, &datastore.ListOptions{
|
||||
FilterOptions: datastore.FilterOptions{
|
||||
IsNotExist: []datastore.IsNotExistQueryOption{{
|
||||
Key: "envName",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
policies, err := repository.ListApplicationCommonPolicies(ctx, c.Store, appModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policy.EnvName = env.Name
|
||||
envPolicies, err := c.Store.List(ctx, &policy, &datastore.ListOptions{})
|
||||
envPolicies, err := repository.ListApplicationEnvPolicies(ctx, c.Store, appModel, env.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -903,8 +877,7 @@ func (c *applicationServiceImpl) renderOAMApplication(ctx context.Context, appMo
|
||||
app.Spec.Components = append(app.Spec.Components, bc)
|
||||
}
|
||||
|
||||
for _, entity := range policies {
|
||||
policy := entity.(*model.ApplicationPolicy)
|
||||
for _, policy := range policies {
|
||||
appPolicy := v1beta1.AppPolicy{
|
||||
Name: policy.Name,
|
||||
Type: policy.Type,
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -463,6 +463,8 @@ func destroySyncConfigsApp(ctx context.Context, k8sClient client.Client, project
|
||||
if !kerrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
klog.InfoS("config sync application doesn't exist, no need destroy", "application", name)
|
||||
return nil
|
||||
}
|
||||
return k8sClient.Delete(ctx, app)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -204,10 +204,7 @@ func (e *envBindingServiceImpl) DeleteEnvBinding(ctx context.Context, appModel *
|
||||
}
|
||||
|
||||
// delete the topology and env-bindings policies
|
||||
if err := e.Store.Delete(ctx, &model.ApplicationPolicy{AppPrimaryKey: appModel.PrimaryKey(), EnvName: envName}); err != nil && !errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
return fmt.Errorf("fail to clear the policies belong to the env %w", err)
|
||||
}
|
||||
return nil
|
||||
return repository.DeleteApplicationEnvPolicies(ctx, e.Store, appModel, envName)
|
||||
}
|
||||
|
||||
func (e *envBindingServiceImpl) BatchDeleteEnvBinding(ctx context.Context, app *model.Application) error {
|
||||
|
||||
@@ -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",
|
||||
@@ -99,7 +98,7 @@ var _ = Describe("Test envBindingService functions", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(base.Name, req.Name)).Should(BeEmpty())
|
||||
|
||||
By("auto create two workflow")
|
||||
By("test the auto created workflow")
|
||||
workflow, err := workflowService.GetWorkflow(context.TODO(), testApp, repository.ConvertWorkflowName("envbinding-dev"))
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(workflow.Steps[0].Name, "dev-target")).Should(BeEmpty())
|
||||
@@ -139,15 +138,19 @@ var _ = Describe("Test envBindingService functions", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
_, err = workflowService.GetWorkflow(context.TODO(), testApp, repository.ConvertWorkflowName("envbinding-dev"))
|
||||
Expect(err).ShouldNot(BeNil())
|
||||
|
||||
err = envBindingService.DeleteEnvBinding(context.TODO(), testApp, "envbinding-prod")
|
||||
Expect(err).Should(BeNil())
|
||||
_, err = workflowService.GetWorkflow(context.TODO(), testApp, repository.ConvertWorkflowName("envbinding-prod"))
|
||||
Expect(err).ShouldNot(BeNil())
|
||||
policies, err := repository.ListApplicationPolicies(context.TODO(), ds, testApp)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(policies)).Should(Equal(0))
|
||||
})
|
||||
|
||||
It("Test Application BatchCreateEnv function", func() {
|
||||
testBatchApp := &model.Application{
|
||||
Name: "test-batch-createt",
|
||||
Name: "test-batch-created",
|
||||
}
|
||||
err := envBindingService.BatchCreateEnvBinding(context.TODO(), testBatchApp, apisv1.EnvBindingList{&envBindingDemo1, &envBindingDemo2})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
228
pkg/apiserver/domain/service/image.go
Normal file
228
pkg/apiserver/domain/service/image.go
Normal 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
|
||||
}
|
||||
67
pkg/apiserver/domain/service/image_test.go
Normal file
67
pkg/apiserver/domain/service/image_test.go
Normal 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)
|
||||
}
|
||||
@@ -18,15 +18,13 @@ 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"
|
||||
|
||||
@@ -40,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.
|
||||
@@ -58,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 {
|
||||
@@ -363,6 +359,12 @@ func (p *projectServiceImpl) UpdateProject(ctx context.Context, projectName stri
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if _, err := p.AddProjectUser(ctx, projectName, apisv1.AddProjectUserRequest{
|
||||
UserName: req.Owner,
|
||||
UserRoles: []string{"project-admin"},
|
||||
}); err != nil && !errors.Is(err, bcode.ErrProjectUserExist) {
|
||||
return nil, err
|
||||
}
|
||||
project.Owner = req.Owner
|
||||
}
|
||||
err = p.Store.Put(ctx, project)
|
||||
@@ -495,7 +497,11 @@ func (p *projectServiceImpl) GetConfigs(ctx context.Context, projectName, config
|
||||
// legacy providers
|
||||
var providers = &terraformapi.ProviderList{}
|
||||
if err := p.K8sClient.List(ctx, providers, client.InNamespace(types.DefaultAppNamespace)); err != nil {
|
||||
return nil, err
|
||||
// this logic depends on the terraform addon, ignore the no matches kind error before the terraform addon is installed.
|
||||
if !meta.IsNoMatchError(err) {
|
||||
return nil, err
|
||||
}
|
||||
log.Logger.Infof("terraform Provider CRD is not installed")
|
||||
}
|
||||
for _, p := range providers.Items {
|
||||
if p.Labels[types.LabelConfigCatalog] == types.VelaCoreConfig {
|
||||
@@ -612,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
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
@@ -189,6 +183,27 @@ var _ = Describe("Test project service functions", func() {
|
||||
Expect(base.Description).Should(BeEquivalentTo("Change description"))
|
||||
Expect(base.Owner.Alias).Should(BeEquivalentTo("Administrator"))
|
||||
|
||||
user := &model.User{
|
||||
Name: "admin-2",
|
||||
Alias: "Administrator2",
|
||||
Password: "ddddd",
|
||||
Disabled: false,
|
||||
}
|
||||
err = projectService.Store.Add(context.TODO(), user)
|
||||
Expect(err).Should(BeNil())
|
||||
base, err = projectService.UpdateProject(context.TODO(), "test-project", apisv1.UpdateProjectRequest{
|
||||
Alias: "Change alias",
|
||||
Description: "Change description",
|
||||
Owner: "admin-2",
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(base.Alias).Should(BeEquivalentTo("Change alias"))
|
||||
Expect(base.Description).Should(BeEquivalentTo("Change description"))
|
||||
Expect(base.Owner.Alias).Should(BeEquivalentTo("Administrator2"))
|
||||
res, err := projectService.ListProjectUser(context.TODO(), "test-project", 0, 0)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(res.Total).Should(Equal(int64(2)))
|
||||
|
||||
_, err = projectService.UpdateProject(context.TODO(), "test-project", apisv1.UpdateProjectRequest{
|
||||
Alias: "Change alias",
|
||||
Description: "Change description",
|
||||
@@ -278,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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,11 @@ import (
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/repository"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/infrastructure/datastore"
|
||||
assembler "github.com/oam-dev/kubevela/pkg/apiserver/interfaces/api/assembler/v1"
|
||||
apisv1 "github.com/oam-dev/kubevela/pkg/apiserver/interfaces/api/dto/v1"
|
||||
apiserverutils "github.com/oam-dev/kubevela/pkg/apiserver/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/bcode"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
@@ -51,7 +54,7 @@ var defaultProjectPermissionTemplate = []*model.PermissionTemplate{
|
||||
{
|
||||
Name: "app-management",
|
||||
Alias: "App Management",
|
||||
Resources: []string{"project:{projectName}/application:*/*", "definition:*"},
|
||||
Resources: []string{"project:{projectName}/application:*/*"},
|
||||
Actions: []string{"*"},
|
||||
Effect: "Allow",
|
||||
Scope: "project",
|
||||
@@ -72,6 +75,14 @@ var defaultProjectPermissionTemplate = []*model.PermissionTemplate{
|
||||
Effect: "Allow",
|
||||
Scope: "project",
|
||||
},
|
||||
{
|
||||
Name: "configuration-read",
|
||||
Alias: "Environment Management",
|
||||
Resources: []string{"project:{projectName}/config:*"},
|
||||
Actions: []string{"list", "detail"},
|
||||
Effect: "Allow",
|
||||
Scope: "project",
|
||||
},
|
||||
}
|
||||
|
||||
var defaultPlatformPermission = []*model.PermissionTemplate{
|
||||
@@ -123,6 +134,14 @@ var defaultPlatformPermission = []*model.PermissionTemplate{
|
||||
Effect: "Allow",
|
||||
Scope: "platform",
|
||||
},
|
||||
{
|
||||
Name: "integration-management",
|
||||
Alias: "Integration Management",
|
||||
Resources: []string{"configType:*/*"},
|
||||
Actions: []string{"*"},
|
||||
Effect: "Allow",
|
||||
Scope: "platform",
|
||||
},
|
||||
{
|
||||
Name: "admin",
|
||||
Alias: "Admin",
|
||||
@@ -182,8 +201,7 @@ var ResourceMaps = map[string]resourceMetadata{
|
||||
pathName: "userName",
|
||||
},
|
||||
"applicationTemplate": {},
|
||||
"configs": {},
|
||||
"image": {},
|
||||
"config": {},
|
||||
},
|
||||
pathName: "projectName",
|
||||
},
|
||||
@@ -205,8 +223,10 @@ var ResourceMaps = map[string]resourceMetadata{
|
||||
"user": {
|
||||
pathName: "userName",
|
||||
},
|
||||
"role": {},
|
||||
"permission": {},
|
||||
"role": {},
|
||||
"permission": {
|
||||
pathName: "permissionName",
|
||||
},
|
||||
"systemSetting": {},
|
||||
"definition": {
|
||||
pathName: "definitionName",
|
||||
@@ -325,6 +345,7 @@ type RBACService interface {
|
||||
ListRole(ctx context.Context, projectName string, page, pageSize int) (*apisv1.ListRolesResponse, error)
|
||||
ListPermissionTemplate(ctx context.Context, projectName string) ([]apisv1.PermissionTemplateBase, error)
|
||||
ListPermissions(ctx context.Context, projectName string) ([]apisv1.PermissionBase, error)
|
||||
CreatePermission(ctx context.Context, projectName string, req apisv1.CreatePermissionRequest) (*apisv1.PermissionBase, error)
|
||||
DeletePermission(ctx context.Context, projectName, permName string) error
|
||||
InitDefaultRoleAndUsersForProject(ctx context.Context, project *model.Project) error
|
||||
Init(ctx context.Context) error
|
||||
@@ -429,9 +450,9 @@ func (p *rbacServiceImpl) GetUserPermissions(ctx context.Context, user *model.Us
|
||||
return perms, nil
|
||||
}
|
||||
|
||||
func (p *rbacServiceImpl) UpdatePermission(ctx context.Context, projetName string, permissionName string, req *apisv1.UpdatePermissionRequest) (*apisv1.PermissionBase, error) {
|
||||
func (p *rbacServiceImpl) UpdatePermission(ctx context.Context, projectName string, permissionName string, req *apisv1.UpdatePermissionRequest) (*apisv1.PermissionBase, error) {
|
||||
perm := &model.Permission{
|
||||
Project: projetName,
|
||||
Project: projectName,
|
||||
Name: permissionName,
|
||||
}
|
||||
err := p.Store.Get(ctx, perm)
|
||||
@@ -539,6 +560,7 @@ func (p *rbacServiceImpl) CheckPerm(resource string, actions ...string) func(req
|
||||
}
|
||||
return req.PathParameter(name)
|
||||
})
|
||||
ra.SetActions(actions)
|
||||
|
||||
// get user's perm list.
|
||||
projectName := getProjectName()
|
||||
@@ -552,6 +574,7 @@ func (p *rbacServiceImpl) CheckPerm(resource string, actions ...string) func(req
|
||||
bcode.ReturnError(req, res, bcode.ErrForbidden)
|
||||
return
|
||||
}
|
||||
apiserverutils.SetUsernameAndProjectInRequestContext(req, userName, projectName)
|
||||
chain.ProcessFilter(req, res)
|
||||
}
|
||||
return f
|
||||
@@ -585,7 +608,7 @@ func (p *rbacServiceImpl) CreateRole(ctx context.Context, projectName string, re
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return ConvertRole2Model(&role, policies), nil
|
||||
return assembler.ConvertRole2DTO(&role, policies), nil
|
||||
}
|
||||
|
||||
func (p *rbacServiceImpl) DeleteRole(ctx context.Context, projectName, roleName string) error {
|
||||
@@ -603,6 +626,19 @@ func (p *rbacServiceImpl) DeleteRole(ctx context.Context, projectName, roleName
|
||||
}
|
||||
|
||||
func (p *rbacServiceImpl) DeletePermission(ctx context.Context, projectName, permName string) error {
|
||||
roles, _, err := repository.ListRoles(ctx, p.Store, projectName, 0, 0)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to list the roles: %s", err.Error())
|
||||
return bcode.ErrPermissionIsUsed
|
||||
}
|
||||
for _, role := range roles {
|
||||
for _, p := range role.Permissions {
|
||||
if p == permName {
|
||||
return bcode.ErrPermissionIsUsed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var perm = model.Permission{
|
||||
Name: permName,
|
||||
Project: projectName,
|
||||
@@ -647,26 +683,17 @@ func (p *rbacServiceImpl) UpdateRole(ctx context.Context, projectName, roleName
|
||||
if err := p.Store.Put(ctx, &role); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ConvertRole2Model(&role, policies), nil
|
||||
return assembler.ConvertRole2DTO(&role, policies), nil
|
||||
}
|
||||
|
||||
func (p *rbacServiceImpl) ListRole(ctx context.Context, projectName string, page, pageSize int) (*apisv1.ListRolesResponse, error) {
|
||||
var role = model.Role{
|
||||
Project: projectName,
|
||||
}
|
||||
var filter datastore.FilterOptions
|
||||
if projectName == "" {
|
||||
filter.IsNotExist = append(filter.IsNotExist, datastore.IsNotExistQueryOption{
|
||||
Key: "project",
|
||||
})
|
||||
}
|
||||
entities, err := p.Store.List(ctx, &role, &datastore.ListOptions{FilterOptions: filter, Page: page, PageSize: pageSize, SortBy: []datastore.SortOption{{Key: "createTime", Order: datastore.SortOrderDescending}}})
|
||||
roles, count, err := repository.ListRoles(ctx, p.Store, projectName, 0, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var policySet = make(map[string]string)
|
||||
for _, entity := range entities {
|
||||
for _, p := range entity.(*model.Role).Permissions {
|
||||
for _, role := range roles {
|
||||
for _, p := range role.Permissions {
|
||||
policySet[p] = p
|
||||
}
|
||||
}
|
||||
@@ -680,17 +707,12 @@ func (p *rbacServiceImpl) ListRole(ctx context.Context, projectName string, page
|
||||
policyMap[policy.Name] = policies[i]
|
||||
}
|
||||
var res apisv1.ListRolesResponse
|
||||
for _, entity := range entities {
|
||||
role := entity.(*model.Role)
|
||||
for _, role := range roles {
|
||||
var rolePolicies []*model.Permission
|
||||
for _, perm := range role.Permissions {
|
||||
rolePolicies = append(rolePolicies, policyMap[perm])
|
||||
}
|
||||
res.Roles = append(res.Roles, ConvertRole2Model(entity.(*model.Role), rolePolicies))
|
||||
}
|
||||
count, err := p.Store.Count(ctx, &role, &filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
res.Roles = append(res.Roles, assembler.ConvertRole2DTO(role, rolePolicies))
|
||||
}
|
||||
res.Total = count
|
||||
return &res, nil
|
||||
@@ -728,11 +750,50 @@ func (p *rbacServiceImpl) ListPermissions(ctx context.Context, projectName strin
|
||||
return perms, nil
|
||||
}
|
||||
|
||||
func (p *rbacServiceImpl) CreatePermission(ctx context.Context, projectName string, req apisv1.CreatePermissionRequest) (*apisv1.PermissionBase, error) {
|
||||
if projectName != "" {
|
||||
var project = model.Project{
|
||||
Name: projectName,
|
||||
}
|
||||
if err := p.Store.Get(ctx, &project); err != nil {
|
||||
return nil, bcode.ErrProjectIsNotExist
|
||||
}
|
||||
}
|
||||
if len(req.Resources) == 0 {
|
||||
return nil, bcode.ErrRolePermissionCheckFailure
|
||||
}
|
||||
|
||||
if len(req.Actions) == 0 {
|
||||
req.Actions = []string{"*"}
|
||||
}
|
||||
|
||||
if req.Effect == "" {
|
||||
req.Effect = "Allow"
|
||||
}
|
||||
|
||||
var permission = model.Permission{
|
||||
Name: req.Name,
|
||||
Alias: req.Alias,
|
||||
Project: projectName,
|
||||
Resources: req.Resources,
|
||||
Actions: req.Actions,
|
||||
Effect: req.Effect,
|
||||
}
|
||||
|
||||
if err := p.Store.Add(ctx, &permission); err != nil {
|
||||
if errors.Is(err, datastore.ErrRecordExist) {
|
||||
return nil, bcode.ErrPermissionIsExist
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return assembler.ConvertPermission2DTO(&permission), nil
|
||||
}
|
||||
|
||||
func (p *rbacServiceImpl) InitDefaultRoleAndUsersForProject(ctx context.Context, project *model.Project) error {
|
||||
var batchData []datastore.Entity
|
||||
for _, permissionTemp := range defaultProjectPermissionTemplate {
|
||||
var rra = RequestResourceAction{}
|
||||
var formatedResource []string
|
||||
var formattedResource []string
|
||||
for _, resource := range permissionTemp.Resources {
|
||||
rra.SetResourceWithName(resource, func(name string) string {
|
||||
if name == ResourceMaps["project"].pathName {
|
||||
@@ -740,13 +801,13 @@ func (p *rbacServiceImpl) InitDefaultRoleAndUsersForProject(ctx context.Context,
|
||||
}
|
||||
return ""
|
||||
})
|
||||
formatedResource = append(formatedResource, rra.GetResource().String())
|
||||
formattedResource = append(formattedResource, rra.GetResource().String())
|
||||
}
|
||||
batchData = append(batchData, &model.Permission{
|
||||
Name: permissionTemp.Name,
|
||||
Alias: permissionTemp.Alias,
|
||||
Project: project.Name,
|
||||
Resources: formatedResource,
|
||||
Resources: formattedResource,
|
||||
Actions: permissionTemp.Actions,
|
||||
Effect: permissionTemp.Effect,
|
||||
})
|
||||
@@ -754,12 +815,12 @@ func (p *rbacServiceImpl) InitDefaultRoleAndUsersForProject(ctx context.Context,
|
||||
batchData = append(batchData, &model.Role{
|
||||
Name: "app-developer",
|
||||
Alias: "App Developer",
|
||||
Permissions: []string{"project-read", "app-management", "env-management"},
|
||||
Permissions: []string{"project-read", "app-management", "env-management", "configuration-read"},
|
||||
Project: project.Name,
|
||||
}, &model.Role{
|
||||
Name: "project-admin",
|
||||
Alias: "Project Admin",
|
||||
Permissions: []string{"project-read", "app-management", "env-management", "role-management"},
|
||||
Permissions: []string{"project-read", "app-management", "env-management", "role-management", "configuration-read"},
|
||||
Project: project.Name,
|
||||
})
|
||||
if project.Owner != "" {
|
||||
@@ -773,24 +834,6 @@ func (p *rbacServiceImpl) InitDefaultRoleAndUsersForProject(ctx context.Context,
|
||||
return p.Store.BatchAdd(ctx, batchData)
|
||||
}
|
||||
|
||||
// ConvertRole2Model convert role model to role base struct
|
||||
func ConvertRole2Model(role *model.Role, policies []*model.Permission) *apisv1.RoleBase {
|
||||
return &apisv1.RoleBase{
|
||||
CreateTime: role.CreateTime,
|
||||
UpdateTime: role.UpdateTime,
|
||||
Name: role.Name,
|
||||
Alias: role.Alias,
|
||||
Permissions: func() (list []apisv1.NameAlias) {
|
||||
for _, policy := range policies {
|
||||
if policy != nil {
|
||||
list = append(list, apisv1.NameAlias{Name: policy.Name, Alias: policy.Alias})
|
||||
}
|
||||
}
|
||||
return
|
||||
}(),
|
||||
}
|
||||
}
|
||||
|
||||
// ResourceName it is similar to ARNs
|
||||
// <type>:<value>/<type>:<value>
|
||||
type ResourceName struct {
|
||||
|
||||
@@ -51,6 +51,10 @@ var _ = Describe("Test rbac service", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(path).Should(BeEquivalentTo("project:{projectName}/application:{appName}"))
|
||||
|
||||
path, err = checkResourcePath("environment")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(path).Should(BeEquivalentTo("project:{projectName}/environment:{envName}"))
|
||||
|
||||
_, err = checkResourcePath("applications")
|
||||
Expect(err).ShouldNot(BeNil())
|
||||
|
||||
@@ -94,7 +98,7 @@ var _ = Describe("Test rbac service", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
policies, err := rbacService.ListPermissions(context.TODO(), "")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(policies)).Should(BeEquivalentTo(int64(7)))
|
||||
Expect(len(policies)).Should(BeEquivalentTo(int64(8)))
|
||||
})
|
||||
|
||||
It("Test checkPerm by admin user", func() {
|
||||
@@ -194,7 +198,7 @@ var _ = Describe("Test rbac service", func() {
|
||||
|
||||
policies, err := rbacService.ListPermissions(context.TODO(), "init-test")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(policies)).Should(BeEquivalentTo(int64(4)))
|
||||
Expect(len(policies)).Should(BeEquivalentTo(int64(5)))
|
||||
})
|
||||
|
||||
It("Test UpdatePermission", func() {
|
||||
@@ -263,6 +267,21 @@ func TestRequestResourceActionMatch(t *testing.T) {
|
||||
ra5.SetActions([]string{"list"})
|
||||
assert.Equal(t, ra5.Match([]*model.Permission{{Resources: []string{"project:*/application:*"}, Actions: []string{"list"}, Effect: "Allow"}}), true)
|
||||
|
||||
ra6 := &RequestResourceAction{}
|
||||
path, err := checkResourcePath("environment")
|
||||
assert.Equal(t, err, nil)
|
||||
ra6.SetResourceWithName(path, func(name string) string {
|
||||
if name == "projectName" {
|
||||
return "default"
|
||||
}
|
||||
return ""
|
||||
})
|
||||
ra6.SetActions([]string{"create"})
|
||||
assert.Equal(t, ra6.Match([]*model.Permission{{Resources: []string{
|
||||
"project:*/*", "addon:* addonRegistry:*", "target:*", "cluster:*/namespace:*", "user:*", "role:*", "permission:*", "configType:*/*", "project:*",
|
||||
"project:default/config:*", "project:default/role:*", "project:default/projectUser:*", "project:default/permission:*", "project:default/environment:*", "project:default/application:*/*", "project:default",
|
||||
}, Actions: []string{"list", "detail"}, Effect: "Allow"}}), false)
|
||||
|
||||
}
|
||||
|
||||
func TestRegisterResourceAction(t *testing.T) {
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -27,8 +28,10 @@ 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"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/bcode"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
"github.com/oam-dev/kubevela/pkg/auth"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
)
|
||||
|
||||
@@ -117,6 +120,9 @@ func (dt *targetServiceImpl) DeleteTarget(ctx context.Context, targetName string
|
||||
if err = repository.DeleteTargetNamespace(ctx, dt.K8sClient, ddt.Cluster.ClusterName, ddt.Cluster.Namespace, targetName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = managePrivilegesForTarget(ctx, dt.K8sClient, ddt, true); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = dt.Store.Delete(ctx, target); err != nil {
|
||||
if errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
return bcode.ErrTargetNotExist
|
||||
@@ -142,6 +148,9 @@ func (dt *targetServiceImpl) CreateTarget(ctx context.Context, req apisv1.Create
|
||||
if err := repository.CreateTargetNamespace(ctx, dt.K8sClient, req.Cluster.ClusterName, req.Cluster.Namespace, req.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := managePrivilegesForTarget(ctx, dt.K8sClient, &target, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err := repository.CreateTarget(ctx, dt.Store, &target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -227,3 +236,22 @@ func (dt *targetServiceImpl) convertFromTargetModel(ctx context.Context, target
|
||||
}
|
||||
return targetBase
|
||||
}
|
||||
|
||||
// managePrivilegesForTarget grant or revoke privileges for target
|
||||
func managePrivilegesForTarget(ctx context.Context, cli client.Client, target *model.Target, revoke bool) error {
|
||||
if target.Cluster == nil {
|
||||
return nil
|
||||
}
|
||||
p := &auth.ScopedPrivilege{Cluster: target.Cluster.ClusterName, Namespace: target.Cluster.Namespace}
|
||||
identity := &auth.Identity{Groups: []string{utils.KubeVelaProjectGroupPrefix + target.Project}}
|
||||
writer := &bytes.Buffer{}
|
||||
f, msg := auth.GrantPrivileges, "GrantPrivileges"
|
||||
if revoke {
|
||||
f, msg = auth.RevokePrivileges, "RevokePrivileges"
|
||||
}
|
||||
if err := f(ctx, cli, []auth.PrivilegeDescription{p}, identity, writer); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Logger.Debugf("%s: %s", msg, writer.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -33,7 +33,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
initAdminPassword = "VelaUX12345"
|
||||
// InitAdminPassword the password of first admin user
|
||||
InitAdminPassword = "VelaUX12345"
|
||||
)
|
||||
|
||||
// UserService User manage api
|
||||
@@ -70,7 +71,7 @@ func (u *userServiceImpl) Init(ctx context.Context) error {
|
||||
Name: admin,
|
||||
}); err != nil {
|
||||
if errors.Is(err, datastore.ErrRecordNotExist) {
|
||||
encrypted, err := GeneratePasswordHash(initAdminPassword)
|
||||
encrypted, err := GeneratePasswordHash(InitAdminPassword)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -83,7 +84,7 @@ func (u *userServiceImpl) Init(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
// print default password of admin user in log
|
||||
log.Logger.Infof("initialized admin username and password: admin / %s", initAdminPassword)
|
||||
log.Logger.Infof("initialized admin username and password: admin / %s", InitAdminPassword)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -37,24 +37,14 @@ type VelaQLService interface {
|
||||
}
|
||||
|
||||
type velaQLServiceImpl struct {
|
||||
kubeClient client.Client
|
||||
kubeConfig *rest.Config
|
||||
KubeClient client.Client `inject:"kubeClient"`
|
||||
KubeConfig *rest.Config `inject:"kubeConfig"`
|
||||
dm discoverymapper.DiscoveryMapper
|
||||
pd *packages.PackageDiscover
|
||||
}
|
||||
|
||||
// NewVelaQLService new velaQL service
|
||||
func NewVelaQLService() VelaQLService {
|
||||
k8sClient, err := clients.GetKubeClient()
|
||||
if err != nil {
|
||||
log.Logger.Fatalf("get kubeclient failure %s", err.Error())
|
||||
}
|
||||
|
||||
kubeConfig, err := clients.GetKubeConfig()
|
||||
if err != nil {
|
||||
log.Logger.Fatalf("get kubeconfig failure %s", err.Error())
|
||||
}
|
||||
|
||||
dm, err := clients.GetDiscoverMapper()
|
||||
if err != nil {
|
||||
log.Logger.Fatalf("get discover mapper failure %s", err.Error())
|
||||
@@ -65,10 +55,8 @@ func NewVelaQLService() VelaQLService {
|
||||
log.Logger.Fatalf("get package discover failure %s", err.Error())
|
||||
}
|
||||
return &velaQLServiceImpl{
|
||||
kubeClient: k8sClient,
|
||||
kubeConfig: kubeConfig,
|
||||
dm: dm,
|
||||
pd: pd,
|
||||
dm: dm,
|
||||
pd: pd,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +67,7 @@ func (v *velaQLServiceImpl) QueryView(ctx context.Context, velaQL string) (*apis
|
||||
return nil, bcode.ErrParseVelaQL
|
||||
}
|
||||
|
||||
queryValue, err := velaql.NewViewHandler(v.kubeClient, v.kubeConfig, v.dm, v.pd).QueryView(ctx, query)
|
||||
queryValue, err := velaql.NewViewHandler(v.KubeClient, v.KubeConfig, v.dm, v.pd).QueryView(ctx, query)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to query the view %s", err.Error())
|
||||
return nil, bcode.ErrViewQuery
|
||||
@@ -88,6 +76,7 @@ func (v *velaQLServiceImpl) QueryView(ctx context.Context, velaQL string) (*apis
|
||||
resp := apis.VelaQLViewResponse{}
|
||||
err = queryValue.UnmarshalTo(&resp)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("decode the velaQL response to json failure %s", err.Error())
|
||||
return nil, bcode.ErrParseQuery2Json
|
||||
}
|
||||
return &resp, err
|
||||
|
||||
@@ -43,6 +43,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
utils2 "github.com/oam-dev/kubevela/pkg/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/apply"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow/tasks/custom"
|
||||
)
|
||||
|
||||
// WorkflowService workflow manage api
|
||||
@@ -577,8 +578,7 @@ func (w *workflowServiceImpl) TerminateRecord(ctx context.Context, appModel *mod
|
||||
return err
|
||||
}
|
||||
|
||||
oamApp.Status.Workflow.Terminated = true
|
||||
if err := w.KubeClient.Status().Patch(ctx, oamApp, client.Merge); err != nil {
|
||||
if err := TerminateWorkflow(ctx, w.KubeClient, oamApp); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.syncWorkflowStatus(ctx, oamApp, recordName, oamApp.Name); err != nil {
|
||||
@@ -588,6 +588,42 @@ func (w *workflowServiceImpl) TerminateRecord(ctx context.Context, appModel *mod
|
||||
return nil
|
||||
}
|
||||
|
||||
// TerminateWorkflow terminate workflow
|
||||
func TerminateWorkflow(ctx context.Context, kubecli client.Client, app *v1beta1.Application) error {
|
||||
// set the workflow terminated to true
|
||||
app.Status.Workflow.Terminated = true
|
||||
steps := app.Status.Workflow.Steps
|
||||
for i, step := range steps {
|
||||
switch step.Phase {
|
||||
case common.WorkflowStepPhaseFailed:
|
||||
if step.Reason != custom.StatusReasonFailedAfterRetries {
|
||||
steps[i].Reason = custom.StatusReasonTerminate
|
||||
}
|
||||
case common.WorkflowStepPhaseRunning:
|
||||
steps[i].Phase = common.WorkflowStepPhaseFailed
|
||||
steps[i].Reason = custom.StatusReasonTerminate
|
||||
default:
|
||||
}
|
||||
for j, sub := range step.SubStepsStatus {
|
||||
switch sub.Phase {
|
||||
case common.WorkflowStepPhaseFailed:
|
||||
if sub.Reason != custom.StatusReasonFailedAfterRetries {
|
||||
steps[i].SubStepsStatus[j].Phase = custom.StatusReasonTerminate
|
||||
}
|
||||
case common.WorkflowStepPhaseRunning:
|
||||
steps[i].SubStepsStatus[j].Phase = common.WorkflowStepPhaseFailed
|
||||
steps[i].SubStepsStatus[j].Reason = custom.StatusReasonTerminate
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := kubecli.Status().Patch(ctx, app, client.Merge); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *workflowServiceImpl) RollbackRecord(ctx context.Context, appModel *model.Application, workflow *model.Workflow, recordName, revisionVersion string) error {
|
||||
if revisionVersion == "" {
|
||||
// find the latest complete revision version
|
||||
|
||||
@@ -18,6 +18,7 @@ package clients
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/rest"
|
||||
@@ -25,6 +26,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/config"
|
||||
|
||||
apiConfig "github.com/oam-dev/kubevela/pkg/apiserver/config"
|
||||
"github.com/oam-dev/kubevela/pkg/auth"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/packages"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||
@@ -39,6 +41,18 @@ func SetKubeClient(c client.Client) {
|
||||
kubeClient = c
|
||||
}
|
||||
|
||||
func setKubeConfig(conf *rest.Config) (err error) {
|
||||
if conf == nil {
|
||||
conf, err = config.GetConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
kubeConfig = conf
|
||||
kubeConfig.Wrap(auth.NewImpersonatingRoundTripper)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetKubeConfig generate the kube config from the config of apiserver
|
||||
func SetKubeConfig(c apiConfig.Config) error {
|
||||
conf, err := config.GetConfig()
|
||||
@@ -48,7 +62,7 @@ func SetKubeConfig(c apiConfig.Config) error {
|
||||
kubeConfig = conf
|
||||
kubeConfig.Burst = c.KubeBurst
|
||||
kubeConfig.QPS = float32(c.KubeQPS)
|
||||
return nil
|
||||
return setKubeConfig(kubeConfig)
|
||||
}
|
||||
|
||||
// GetKubeClient create and return kube runtime client
|
||||
@@ -57,11 +71,7 @@ func GetKubeClient() (client.Client, error) {
|
||||
return kubeClient, nil
|
||||
}
|
||||
if kubeConfig == nil {
|
||||
conf, err := config.GetConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kubeConfig = conf
|
||||
return nil, fmt.Errorf("please call SetKubeConfig first")
|
||||
}
|
||||
var err error
|
||||
kubeClient, err = multicluster.Initialize(kubeConfig, false)
|
||||
@@ -81,10 +91,8 @@ func GetKubeClient() (client.Client, error) {
|
||||
|
||||
// GetKubeConfig create/get kube runtime config
|
||||
func GetKubeConfig() (*rest.Config, error) {
|
||||
var err error
|
||||
if kubeConfig == nil {
|
||||
kubeConfig, err = config.GetConfig()
|
||||
return kubeConfig, err
|
||||
return nil, fmt.Errorf("please call SetKubeConfig first")
|
||||
}
|
||||
return kubeConfig, nil
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
})
|
||||
})
|
||||
|
||||
@@ -275,7 +275,7 @@ func (m *mongodb) Count(ctx context.Context, entity datastore.Entity, filterOpti
|
||||
if entity.Index() != nil {
|
||||
for k, v := range entity.Index() {
|
||||
filter = append(filter, bson.E{
|
||||
Key: k,
|
||||
Key: strings.ToLower(k),
|
||||
Value: v,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -232,6 +232,11 @@ var _ = Describe("Test mongodb datastore driver", func() {
|
||||
}})
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(count).Should(Equal(int64(3)))
|
||||
|
||||
app.Name = "kubevela-app-3"
|
||||
count, err = mongodbDriver.Count(context.TODO(), &app, &datastore.FilterOptions{})
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(count).Should(Equal(int64(1)))
|
||||
})
|
||||
|
||||
It("Test isExist function", func() {
|
||||
|
||||
@@ -554,8 +554,9 @@ func (c *applicationAPIInterface) GetWebServiceRoute() *restful.WebService {
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.RbacService.CheckPerm("application", "compare")).
|
||||
Filter(c.appCheckFilter).
|
||||
Reads(apis.AppCompareReq{}).
|
||||
Param(ws.PathParameter("appName", "identifier of the application ").DataType("string")).
|
||||
Returns(200, "OK", apis.ApplicationBase{}).
|
||||
Returns(200, "OK", apis.AppCompareResponse{}).
|
||||
Returns(400, "Bad Request", bcode.Bcode{}).
|
||||
Writes(apis.AppCompareResponse{}))
|
||||
|
||||
@@ -574,6 +575,7 @@ func (c *applicationAPIInterface) GetWebServiceRoute() *restful.WebService {
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(c.RbacService.CheckPerm("application", "detail")).
|
||||
Filter(c.appCheckFilter).
|
||||
Reads(apis.AppDryRunReq{}).
|
||||
Param(ws.PathParameter("appName", "identifier of the application ").DataType("string")).
|
||||
Returns(200, "OK", apis.AppDryRunResponse{}).
|
||||
Returns(400, "Bad Request", bcode.Bcode{}).
|
||||
|
||||
@@ -201,6 +201,40 @@ func ConvertPolicyModelToBase(policy *model.ApplicationPolicy) *apisv1.PolicyBas
|
||||
return pb
|
||||
}
|
||||
|
||||
// ConvertRole2DTO convert role model to role base struct
|
||||
func ConvertRole2DTO(role *model.Role, policies []*model.Permission) *apisv1.RoleBase {
|
||||
return &apisv1.RoleBase{
|
||||
CreateTime: role.CreateTime,
|
||||
UpdateTime: role.UpdateTime,
|
||||
Name: role.Name,
|
||||
Alias: role.Alias,
|
||||
Permissions: func() (list []apisv1.NameAlias) {
|
||||
for _, policy := range policies {
|
||||
if policy != nil {
|
||||
list = append(list, apisv1.NameAlias{Name: policy.Name, Alias: policy.Alias})
|
||||
}
|
||||
}
|
||||
return
|
||||
}(),
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertPermission2DTO convert permission model to the DTO
|
||||
func ConvertPermission2DTO(permission *model.Permission) *apisv1.PermissionBase {
|
||||
if permission == nil {
|
||||
return nil
|
||||
}
|
||||
return &apisv1.PermissionBase{
|
||||
Name: permission.Name,
|
||||
Alias: permission.Alias,
|
||||
Resources: permission.Resources,
|
||||
Actions: permission.Actions,
|
||||
Effect: permission.Effect,
|
||||
CreateTime: permission.CreateTime,
|
||||
UpdateTime: permission.UpdateTime,
|
||||
}
|
||||
}
|
||||
|
||||
func convertBool(b *bool) bool {
|
||||
if b == nil {
|
||||
return false
|
||||
|
||||
@@ -65,7 +65,7 @@ func (s *configAPIInterface) GetWebServiceRoute() *restful.WebService {
|
||||
ws.Route(ws.POST("/{configType}").To(s.createConfig).
|
||||
Doc("create or update a config").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(s.RbacService.CheckPerm("configType", "create")).
|
||||
Filter(s.RbacService.CheckPerm("configType/config", "create")).
|
||||
Param(ws.PathParameter("configType", "identifier of the config type").DataType("string")).
|
||||
Reads(apis.CreateConfigRequest{}).
|
||||
Returns(200, "OK", apis.EmptyResponse{}).
|
||||
@@ -76,7 +76,7 @@ func (s *configAPIInterface) GetWebServiceRoute() *restful.WebService {
|
||||
ws.Route(ws.GET("/{configType}/configs").To(s.getConfigs).
|
||||
Doc("get configs from a config type").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(s.RbacService.CheckPerm("config", "list")).
|
||||
Filter(s.RbacService.CheckPerm("configType/config", "list")).
|
||||
Param(ws.PathParameter("configType", "identifier of the config").DataType("string")).
|
||||
Returns(200, "OK", []*apis.Config{}).
|
||||
Returns(400, "Bad Request", bcode.Bcode{}).
|
||||
@@ -85,7 +85,7 @@ func (s *configAPIInterface) GetWebServiceRoute() *restful.WebService {
|
||||
ws.Route(ws.GET("/{configType}/configs/{name}").To(s.getConfig).
|
||||
Doc("get a config from a config type").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(s.RbacService.CheckPerm("config", "get")).
|
||||
Filter(s.RbacService.CheckPerm("configType/config", "get")).
|
||||
Param(ws.PathParameter("configType", "identifier of the config type").DataType("string")).
|
||||
Param(ws.PathParameter("name", "identifier of the config").DataType("string")).
|
||||
Returns(200, "OK", []*apis.Config{}).
|
||||
@@ -95,7 +95,7 @@ func (s *configAPIInterface) GetWebServiceRoute() *restful.WebService {
|
||||
ws.Route(ws.DELETE("/{configType}/configs/{name}").To(s.deleteConfig).
|
||||
Doc("delete a config").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(s.RbacService.CheckPerm("config", "delete")).
|
||||
Filter(s.RbacService.CheckPerm("configType/config", "delete")).
|
||||
Param(ws.PathParameter("configType", "identifier of the config type").DataType("string")).
|
||||
Param(ws.PathParameter("name", "identifier of the config").DataType("string")).
|
||||
Returns(200, "OK", apis.EmptyResponse{}).
|
||||
|
||||
@@ -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"
|
||||
@@ -1345,7 +1346,7 @@ type PermissionBase struct {
|
||||
UpdateTime time.Time `json:"updateTime"`
|
||||
}
|
||||
|
||||
// UpdatePermissionRequest the request body that update permission policy
|
||||
// UpdatePermissionRequest the request body that updating a permission policy
|
||||
type UpdatePermissionRequest struct {
|
||||
Alias string `json:"alias" validate:"checkalias"`
|
||||
Resources []string `json:"resources"`
|
||||
@@ -1353,6 +1354,15 @@ type UpdatePermissionRequest struct {
|
||||
Effect string `json:"effect" validate:"oneof=Allow Deny"`
|
||||
}
|
||||
|
||||
// CreatePermissionRequest the request body that creating a permission policy
|
||||
type CreatePermissionRequest struct {
|
||||
Name string `json:"name" validate:"checkname"`
|
||||
Alias string `json:"alias" validate:"checkalias"`
|
||||
Resources []string `json:"resources"`
|
||||
Actions []string `json:"actions"`
|
||||
Effect string `json:"effect" validate:"oneof=Allow Deny"`
|
||||
}
|
||||
|
||||
// LoginUserInfoResponse the response body of login user info
|
||||
type LoginUserInfoResponse struct {
|
||||
UserBase
|
||||
@@ -1371,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"`
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func (n *envAPIInterface) GetWebServiceRoute() *restful.WebService {
|
||||
Doc("update an env").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(n.RBACService.CheckPerm("environment", "update")).
|
||||
Param(ws.PathParameter("envName", "identifier of the application ").DataType("string")).
|
||||
Param(ws.PathParameter("envName", "identifier of the environment").DataType("string")).
|
||||
Reads(apis.CreateEnvRequest{}).
|
||||
Returns(200, "OK", apis.Env{}).
|
||||
Writes(apis.Env{}))
|
||||
@@ -80,7 +80,7 @@ func (n *envAPIInterface) GetWebServiceRoute() *restful.WebService {
|
||||
Doc("delete one env").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(n.RBACService.CheckPerm("environment", "delete")).
|
||||
Param(ws.PathParameter("envName", "identifier of the application ").DataType("string")).
|
||||
Param(ws.PathParameter("envName", "identifier of the environment").DataType("string")).
|
||||
Returns(200, "OK", apis.EmptyResponse{}).
|
||||
Returns(400, "Bad Request", bcode.Bcode{}).
|
||||
Writes(apis.EmptyResponse{}))
|
||||
|
||||
@@ -76,7 +76,7 @@ func InitAPIBean() []interface{} {
|
||||
RegisterAPIInterface(NewTargetAPIInterface())
|
||||
RegisterAPIInterface(NewVelaQLAPIInterface())
|
||||
RegisterAPIInterface(NewWebhookAPIInterface())
|
||||
RegisterAPIInterface(NewHelmAPIInterface())
|
||||
RegisterAPIInterface(NewRepositoryAPIInterface())
|
||||
|
||||
// Authentication
|
||||
RegisterAPIInterface(NewAuthenticationAPIInterface())
|
||||
|
||||
@@ -176,26 +176,33 @@ func (n *projectAPIInterface) GetWebServiceRoute() *restful.WebService {
|
||||
Returns(200, "OK", []apis.PermissionBase{}).
|
||||
Writes([]apis.PermissionBase{}))
|
||||
|
||||
ws.Route(ws.POST("/{projectName}/permissions").To(n.createProjectPermission).
|
||||
Doc("create a project level perm policy").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Param(ws.PathParameter("projectName", "identifier of the project").DataType("string")).
|
||||
Filter(n.RbacService.CheckPerm("project/permission", "list")).
|
||||
Returns(200, "OK", []apis.PermissionBase{}).
|
||||
Writes([]apis.PermissionBase{}))
|
||||
|
||||
ws.Route(ws.DELETE("/{projectName}/permissions/{permissionName}").To(n.deleteProjectPermission).
|
||||
Doc("delete a project level perm policy").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Param(ws.PathParameter("projectName", "identifier of the project").DataType("string")).
|
||||
Param(ws.PathParameter("permissionName", "identifier of the permission").DataType("string")).
|
||||
Filter(n.RbacService.CheckPerm("project/permission", "list")).
|
||||
Returns(200, "OK", []apis.PermissionBase{}).
|
||||
Writes([]apis.PermissionBase{}))
|
||||
|
||||
ws.Route(ws.GET("/{projectName}/configs").To(n.getConfigs).
|
||||
Doc("get configs which are in a project").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Filter(n.RbacService.CheckPerm("project/configs", "list")).
|
||||
Filter(n.RbacService.CheckPerm("project/config", "list")).
|
||||
Param(ws.QueryParameter("configType", "config type").DataType("string")).
|
||||
Param(ws.PathParameter("projectName", "identifier of the project").DataType("string")).
|
||||
Returns(200, "OK", []*apis.Config{}).
|
||||
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
|
||||
}
|
||||
@@ -524,6 +531,45 @@ func (n *projectAPIInterface) listProjectPermissions(req *restful.Request, res *
|
||||
}
|
||||
}
|
||||
|
||||
func (n *projectAPIInterface) createProjectPermission(req *restful.Request, res *restful.Response) {
|
||||
// Verify the validity of parameters
|
||||
var createReq apis.CreatePermissionRequest
|
||||
if err := req.ReadEntity(&createReq); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
if err := validate.Struct(&createReq); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
// Call the domain layer code
|
||||
permissionBase, err := n.RbacService.CreatePermission(req.Request.Context(), req.PathParameter("projectName"), createReq)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("create the permission failure %s", err.Error())
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Write back response data
|
||||
if err := res.WriteEntity(permissionBase); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (n *projectAPIInterface) deleteProjectPermission(req *restful.Request, res *restful.Response) {
|
||||
err := n.RbacService.DeletePermission(req.Request.Context(), req.PathParameter("projectName"), req.PathParameter("permissionName"))
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
// Write back response data
|
||||
if err := res.WriteEntity(apis.EmptyResponse{}); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (n *projectAPIInterface) getConfigs(req *restful.Request, res *restful.Response) {
|
||||
configs, err := n.ProjectService.GetConfigs(req.Request.Context(), req.PathParameter("projectName"), req.QueryParameter("configType"))
|
||||
if err != nil {
|
||||
@@ -543,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
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user