mirror of
https://github.com/kubevela/kubevela.git
synced 2026-03-02 09:40:51 +00:00
Compare commits
46 Commits
v1.5.0-bet
...
v1.5.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3df1776b37 | ||
|
|
a6434c3efa | ||
|
|
766594d625 | ||
|
|
f7bd17edd7 | ||
|
|
5213e54466 | ||
|
|
939556a698 | ||
|
|
c8d89a1856 | ||
|
|
891429c5f5 | ||
|
|
8b6dbd781f | ||
|
|
7916e874c5 | ||
|
|
8f78189a79 | ||
|
|
6d979cfcab | ||
|
|
491127daec | ||
|
|
1829cf4e40 | ||
|
|
b0facbeaab | ||
|
|
e29b1af202 | ||
|
|
a3ee8eb01d | ||
|
|
84b4d0f685 | ||
|
|
4e370b940c | ||
|
|
110156aff0 | ||
|
|
62df98818e | ||
|
|
992e636211 | ||
|
|
3a7a8ac59f | ||
|
|
75fd38f1de | ||
|
|
8abd78e5f1 | ||
|
|
2d82e74c5b | ||
|
|
66dfcec0ad | ||
|
|
37dd176dd3 | ||
|
|
da9bd8ca63 | ||
|
|
bc1d24e034 | ||
|
|
bcce87c073 | ||
|
|
3a9e5ccd5d | ||
|
|
1b21db979f | ||
|
|
618596b98e | ||
|
|
db21d74a52 | ||
|
|
fafa18e8db | ||
|
|
acf923dd10 | ||
|
|
8fc94f057f | ||
|
|
6a6dfba79b | ||
|
|
3b7a997b3e | ||
|
|
e13a259bca | ||
|
|
58af7103e7 | ||
|
|
b329923f81 | ||
|
|
6f8cc0f5b4 | ||
|
|
8c9d0ae314 | ||
|
|
b6c024c205 |
15
.github/workflows/chart.yaml
vendored
15
.github/workflows/chart.yaml
vendored
@@ -21,7 +21,11 @@ jobs:
|
||||
MINIMAL_HELM_CHART: charts/vela-minimal
|
||||
LEGACY_HELM_CHART: legacy/charts/vela-core-legacy
|
||||
VELA_ROLLOUT_HELM_CHART: runtime/rollout/charts
|
||||
LOCAL_OSS_DIRECTORY: .oss/
|
||||
LOCAL_OSS_DIRECTORY: .oss
|
||||
HELM_CHART_NAME: vela-core
|
||||
MINIMAL_HELM_CHART_NAME: vela-minimal
|
||||
LEGACY_HELM_CHART_NAME: vela-core-legacy
|
||||
VELA_ROLLOUT_HELM_CHART_NAME: vela-rollout
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
@@ -86,4 +90,11 @@ jobs:
|
||||
helm package $VELA_ROLLOUT_HELM_CHART --destination $LOCAL_OSS_DIRECTORY
|
||||
helm repo index --url https://$BUCKET.$ENDPOINT/core $LOCAL_OSS_DIRECTORY
|
||||
- name: sync local to cloud
|
||||
run: ./ossutil --config-file .ossutilconfig sync $LOCAL_OSS_DIRECTORY oss://$BUCKET/core -f
|
||||
run: |
|
||||
image_tag=${{ steps.get_version.outputs.VERSION }}
|
||||
chart_semver=${image_tag#"v"}
|
||||
./ossutil --config-file .ossutilconfig cp -f $LOCAL_OSS_DIRECTORY/index.yaml oss://$BUCKET/core/index.yaml
|
||||
./ossutil --config-file .ossutilconfig cp -f $LOCAL_OSS_DIRECTORY/$HELM_CHART_NAME-${chart_semver}.tgz oss://$BUCKET/core/$HELM_CHART_NAME-${chart_semver}.tgz
|
||||
./ossutil --config-file .ossutilconfig cp -f $LOCAL_OSS_DIRECTORY/$MINIMAL_HELM_CHART_NAME-${chart_semver}.tgz oss://$BUCKET/core/$MINIMAL_HELM_CHART_NAME-${chart_semver}.tgz
|
||||
./ossutil --config-file .ossutilconfig cp -f $LOCAL_OSS_DIRECTORY/$LEGACY_HELM_CHART_NAME-${chart_semver}.tgz oss://$BUCKET/core/$LEGACY_HELM_CHART_NAME-${chart_semver}.tgz
|
||||
./ossutil --config-file .ossutilconfig cp -f $LOCAL_OSS_DIRECTORY/$VELA_ROLLOUT_HELM_CHART_NAME-${chart_semver}.tgz oss://$BUCKET/core/$VELA_ROLLOUT_HELM_CHART_NAME-${chart_semver}.tgz
|
||||
|
||||
19
.github/workflows/registry.yml
vendored
19
.github/workflows/registry.yml
vendored
@@ -167,25 +167,6 @@ jobs:
|
||||
docker.io/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }}
|
||||
ghcr.io/${{ github.repository_owner }}/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }}
|
||||
${{ secrets.ACR_DOMAIN }}/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }}
|
||||
|
||||
- uses: docker/build-push-action@v2
|
||||
name: Build & Pushing CloudShell for Dockerhub, GHCR and ACR
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.cloudshell
|
||||
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/cloudshell:${{ steps.get_version.outputs.VERSION }}
|
||||
ghcr.io/${{ github.repository_owner }}/oamdev/cloudshell:${{ steps.get_version.outputs.VERSION }}
|
||||
${{ secrets.ACR_DOMAIN }}/oamdev/cloudshell:${{ steps.get_version.outputs.VERSION }}
|
||||
|
||||
publish-capabilities:
|
||||
env:
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
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 VERSION
|
||||
ARG GITVERSION
|
||||
|
||||
RUN GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=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 ./references/cmd/cli/main.go
|
||||
|
||||
FROM ghcr.io/cloudtty/cloudshell:v0.2.0
|
||||
RUN apt-get install -y vim
|
||||
ENV API_TOKEN_PATH=/usr/local/kubeconfig/token
|
||||
COPY --from=builder /workspace/vela /usr/local/bin/vela
|
||||
@@ -53,15 +53,7 @@ func (in ApplyOncePolicySpec) FindStrategy(manifest *unstructured.Unstructured)
|
||||
return nil
|
||||
}
|
||||
for _, rule := range in.Rules {
|
||||
match := func(src []string, val string) (found bool) {
|
||||
for _, _val := range src {
|
||||
found = found || _val == val
|
||||
}
|
||||
return val != "" && found
|
||||
}
|
||||
if (match(rule.Selector.CompNames, manifest.GetName()) && match(rule.Selector.ResourceTypes, manifest.GetKind())) ||
|
||||
(rule.Selector.CompNames == nil && match(rule.Selector.ResourceTypes, manifest.GetKind()) ||
|
||||
(rule.Selector.ResourceTypes == nil && match(rule.Selector.CompNames, manifest.GetName()))) {
|
||||
if rule.Selector.Match(manifest) {
|
||||
return rule.Strategy
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/utils/pointer"
|
||||
"k8s.io/utils/strings/slices"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
@@ -57,20 +58,19 @@ type GarbageCollectPolicyRule struct {
|
||||
}
|
||||
|
||||
// ResourcePolicyRuleSelector select the targets of the rule
|
||||
// 1) for GarbageCollectPolicyRule
|
||||
// if both traitTypes, oamTypes and componentTypes are specified, combination logic is OR
|
||||
// if one resource is specified with conflict strategies, strategy as component go first.
|
||||
// 2) for ApplyOncePolicyRule only CompNames and ResourceTypes are used
|
||||
// if multiple conditions are specified, combination logic is AND
|
||||
type ResourcePolicyRuleSelector struct {
|
||||
CompNames []string `json:"componentNames"`
|
||||
CompTypes []string `json:"componentTypes"`
|
||||
OAMResourceTypes []string `json:"oamTypes"`
|
||||
TraitTypes []string `json:"traitTypes"`
|
||||
ResourceTypes []string `json:"resourceTypes"`
|
||||
ResourceNames []string `json:"resourceNames"`
|
||||
CompNames []string `json:"componentNames,omitempty"`
|
||||
CompTypes []string `json:"componentTypes,omitempty"`
|
||||
OAMResourceTypes []string `json:"oamTypes,omitempty"`
|
||||
TraitTypes []string `json:"traitTypes,omitempty"`
|
||||
ResourceTypes []string `json:"resourceTypes,omitempty"`
|
||||
ResourceNames []string `json:"resourceNames,omitempty"`
|
||||
}
|
||||
|
||||
// Match check if current rule selector match the target resource
|
||||
// If at least one condition is matched and no other condition failed (could be empty), return true
|
||||
// Otherwise, return false
|
||||
func (in *ResourcePolicyRuleSelector) Match(manifest *unstructured.Unstructured) bool {
|
||||
var compName, compType, oamType, traitType, resourceType, resourceName string
|
||||
if labels := manifest.GetLabels(); labels != nil {
|
||||
@@ -81,15 +81,33 @@ func (in *ResourcePolicyRuleSelector) Match(manifest *unstructured.Unstructured)
|
||||
}
|
||||
resourceType = manifest.GetKind()
|
||||
resourceName = manifest.GetName()
|
||||
match := func(src []string, val string) (found bool) {
|
||||
return val != "" && slices.Contains(src, val)
|
||||
match := func(src []string, val string) (found *bool) {
|
||||
if len(src) == 0 {
|
||||
return nil
|
||||
}
|
||||
return pointer.Bool(val != "" && slices.Contains(src, val))
|
||||
}
|
||||
return match(in.CompNames, compName) ||
|
||||
match(in.CompTypes, compType) ||
|
||||
match(in.OAMResourceTypes, oamType) ||
|
||||
match(in.TraitTypes, traitType) ||
|
||||
match(in.ResourceTypes, resourceType) ||
|
||||
match(in.ResourceNames, resourceName)
|
||||
conditions := []*bool{
|
||||
match(in.CompNames, compName),
|
||||
match(in.CompTypes, compType),
|
||||
match(in.OAMResourceTypes, oamType),
|
||||
match(in.TraitTypes, traitType),
|
||||
match(in.ResourceTypes, resourceType),
|
||||
match(in.ResourceNames, resourceName),
|
||||
}
|
||||
hasMatched := false
|
||||
for _, cond := range conditions {
|
||||
// if any non-empty condition failed, return false
|
||||
if cond != nil && !*cond {
|
||||
return false
|
||||
}
|
||||
// if condition succeed, record it
|
||||
if cond != nil && *cond {
|
||||
hasMatched = true
|
||||
}
|
||||
}
|
||||
// if at least one condition is met, return true
|
||||
return hasMatched
|
||||
}
|
||||
|
||||
// GarbageCollectStrategy the strategy for target resource to recycle
|
||||
|
||||
@@ -120,7 +120,7 @@ type TraitDefinitionSpec struct {
|
||||
PodDisruptive bool `json:"podDisruptive,omitempty"`
|
||||
|
||||
// AppliesToWorkloads specifies the list of workload kinds this trait
|
||||
// applies to. Workload kinds are specified in kind.group/version format,
|
||||
// applies to. Workload kinds are specified in resource.group/version format,
|
||||
// e.g. server.core.oam.dev/v1alpha2. Traits that omit this field apply to
|
||||
// all workload kinds.
|
||||
// +optional
|
||||
|
||||
@@ -82,6 +82,8 @@ type ManagedResource struct {
|
||||
Data *runtime.RawExtension `json:"raw,omitempty"`
|
||||
// Deleted marks the resource to be deleted
|
||||
Deleted bool `json:"deleted,omitempty"`
|
||||
// SkipGC marks the resource to skip gc
|
||||
SkipGC bool `json:"skipGC,omitempty"`
|
||||
}
|
||||
|
||||
// Equal check if two managed resource equals
|
||||
@@ -121,12 +123,13 @@ func (in ManagedResource) NamespacedName() types.NamespacedName {
|
||||
|
||||
// ResourceKey computes the key for managed resource, resources with the same key points to the same resource
|
||||
func (in ManagedResource) ResourceKey() string {
|
||||
gv, kind := in.GroupVersionKind().ToAPIVersionAndKind()
|
||||
group := in.GroupVersionKind().Group
|
||||
kind := in.GroupVersionKind().Kind
|
||||
cluster := in.Cluster
|
||||
if cluster == "" {
|
||||
cluster = velatypes.ClusterLocalName
|
||||
}
|
||||
return strings.Join([]string{gv, kind, cluster, in.Namespace, in.Name}, "/")
|
||||
return strings.Join([]string{group, kind, cluster, in.Namespace, in.Name}, "/")
|
||||
}
|
||||
|
||||
// ComponentKey computes the key for the component which managed resource belongs to
|
||||
@@ -215,8 +218,9 @@ func (in *ResourceTracker) ContainsManagedResource(rsc client.Object) bool {
|
||||
}
|
||||
|
||||
// AddManagedResource add object to managed resources, if exists, update
|
||||
func (in *ResourceTracker) AddManagedResource(rsc client.Object, metaOnly bool, creator common.ResourceCreatorRole) (updated bool) {
|
||||
func (in *ResourceTracker) AddManagedResource(rsc client.Object, metaOnly bool, skipGC bool, creator common.ResourceCreatorRole) (updated bool) {
|
||||
mr := newManagedResourceFromResource(rsc)
|
||||
mr.SkipGC = skipGC
|
||||
if !metaOnly {
|
||||
mr.Data = &runtime.RawExtension{Object: rsc}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ func TestManagedResourceKeys(t *testing.T) {
|
||||
},
|
||||
}
|
||||
r.Equal("namespace/name", input.NamespacedName().String())
|
||||
r.Equal("apps/v1/Deployment/cluster/namespace/name", input.ResourceKey())
|
||||
r.Equal("apps/Deployment/cluster/namespace/name", input.ResourceKey())
|
||||
r.Equal("env/component", input.ComponentKey())
|
||||
r.Equal("Deployment name (Cluster: cluster, Namespace: namespace)", input.DisplayName())
|
||||
var deploy1, deploy2 v12.Deployment
|
||||
@@ -156,16 +156,16 @@ func TestResourceTracker_ManagedResource(t *testing.T) {
|
||||
r := require.New(t)
|
||||
input := &ResourceTracker{}
|
||||
deploy1 := v12.Deployment{ObjectMeta: v13.ObjectMeta{Name: "deploy1"}}
|
||||
input.AddManagedResource(&deploy1, true, "")
|
||||
input.AddManagedResource(&deploy1, true, false, "")
|
||||
r.Equal(1, len(input.Spec.ManagedResources))
|
||||
cm2 := v1.ConfigMap{ObjectMeta: v13.ObjectMeta{Name: "cm2"}}
|
||||
input.AddManagedResource(&cm2, false, "")
|
||||
input.AddManagedResource(&cm2, false, false, "")
|
||||
r.Equal(2, len(input.Spec.ManagedResources))
|
||||
pod3 := v1.Pod{ObjectMeta: v13.ObjectMeta{Name: "pod3"}}
|
||||
input.AddManagedResource(&pod3, false, "")
|
||||
input.AddManagedResource(&pod3, false, false, "")
|
||||
r.Equal(3, len(input.Spec.ManagedResources))
|
||||
deploy1.Spec.Replicas = pointer.Int32(5)
|
||||
input.AddManagedResource(&deploy1, false, "")
|
||||
input.AddManagedResource(&deploy1, false, false, "")
|
||||
r.Equal(3, len(input.Spec.ManagedResources))
|
||||
input.DeleteManagedResource(&cm2, false)
|
||||
r.Equal(3, len(input.Spec.ManagedResources))
|
||||
|
||||
@@ -106,6 +106,7 @@ type Config map[string]string
|
||||
type EnvMeta struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
Labels string `json:"labels"`
|
||||
Current string `json:"current"`
|
||||
}
|
||||
|
||||
|
||||
@@ -3650,7 +3650,7 @@ spec:
|
||||
appliesToWorkloads:
|
||||
description: AppliesToWorkloads specifies the list of workload
|
||||
kinds this trait applies to. Workload kinds are specified
|
||||
in kind.group/version format, e.g. server.core.oam.dev/v1alpha2.
|
||||
in resource.group/version format, e.g. server.core.oam.dev/v1alpha2.
|
||||
Traits that omit this field apply to all workload kinds.
|
||||
items:
|
||||
type: string
|
||||
|
||||
@@ -708,7 +708,7 @@ spec:
|
||||
appliesToWorkloads:
|
||||
description: AppliesToWorkloads specifies the list of workload
|
||||
kinds this trait applies to. Workload kinds are specified
|
||||
in kind.group/version format, e.g. server.core.oam.dev/v1alpha2.
|
||||
in resource.group/version format, e.g. server.core.oam.dev/v1alpha2.
|
||||
Traits that omit this field apply to all workload kinds.
|
||||
items:
|
||||
type: string
|
||||
|
||||
@@ -105,6 +105,9 @@ spec:
|
||||
description: 'Specific resourceVersion to which this reference
|
||||
is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
|
||||
type: string
|
||||
skipGC:
|
||||
description: SkipGC marks the resource to skip gc
|
||||
type: boolean
|
||||
trait:
|
||||
type: string
|
||||
uid:
|
||||
|
||||
@@ -356,7 +356,7 @@ spec:
|
||||
properties:
|
||||
appliesToWorkloads:
|
||||
description: AppliesToWorkloads specifies the list of workload kinds
|
||||
this trait applies to. Workload kinds are specified in kind.group/version
|
||||
this trait applies to. Workload kinds are specified in resource.group/version
|
||||
format, e.g. server.core.oam.dev/v1alpha2. Traits that omit this
|
||||
field apply to all workload kinds.
|
||||
items:
|
||||
|
||||
@@ -11,7 +11,10 @@ metadata:
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -4,9 +4,7 @@ apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add annotations on K8s pod for your workload which follows the pod spec in path 'spec.template'.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
definition.oam.dev/description: Add annotations on your workload. if it generates pod, add same annotations for generated pods.
|
||||
name: annotations
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -5,13 +5,14 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add command on K8s pod for your workload which follows the pod spec in path 'spec.template'
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: command
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
|
||||
@@ -5,13 +5,14 @@ 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:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -5,13 +5,12 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Automatically scale the component based on CPU usage.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: cpuscaler
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
|
||||
@@ -5,13 +5,14 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add env on K8s pod for your workload which follows the pod spec in path 'spec.template'
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: env
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
|
||||
@@ -5,11 +5,12 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Expose port to enable web traffic for your component.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: expose
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
podDisruptive: false
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -9,7 +9,8 @@ metadata:
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
podDisruptive: false
|
||||
schematic:
|
||||
cue:
|
||||
@@ -85,7 +86,7 @@ spec:
|
||||
// +usage=Set ingress class in '.spec.ingressClassName' instead of 'kubernetes.io/ingress.class' annotation.
|
||||
classInSpec: *false | bool
|
||||
|
||||
// +usage=Specify the secret name you want to quote.
|
||||
// +usage=Specify the secret name you want to quote to use tls.
|
||||
secretName?: string
|
||||
|
||||
// +usage=Specify the host of the ingress gateway, which is used to generate the endpoints when the host is empty.
|
||||
|
||||
@@ -5,13 +5,14 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add host aliases on K8s pod for your workload which follows the pod spec in path 'spec.template'.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: hostalias
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: false
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/import-grafana-dashboard.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Import dashboards to Grafana
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: import-grafana-dashboard
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads: []
|
||||
conflictsWith: []
|
||||
podDisruptive: false
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
outputs: registerdatasource: {
|
||||
apiVersion: "grafana.extension.oam.dev/v1alpha1"
|
||||
kind: "ImportDashboard"
|
||||
spec: {
|
||||
grafana: {
|
||||
service: parameter.grafanaServiceName
|
||||
namespace: parameter.grafanaServiceNamespace
|
||||
credentialSecret: parameter.credentialSecret
|
||||
credentialSecretNamespace: parameter.credentialSecretNamespace
|
||||
}
|
||||
urls: parameter.urls
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
grafanaServiceName: string
|
||||
grafanaServiceNamespace: *"default" | string
|
||||
credentialSecret: string
|
||||
credentialSecretNamespace: *"default" | string
|
||||
urls: [...string]
|
||||
|
||||
}
|
||||
workloadRefPath: ""
|
||||
|
||||
@@ -5,13 +5,14 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: add an init container and use shared volume with pod
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: init-container
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -4,9 +4,7 @@ apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add labels on K8s pod for your workload which follows the pod spec in path 'spec.template'.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
definition.oam.dev/description: Add labels on your workload. if it generates pod, add same label for generated pods.
|
||||
name: labels
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -5,13 +5,14 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add lifecycle hooks for every container of K8s pod for your workload which follows the pod spec in path 'spec.template'.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: lifecycle
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -11,7 +11,10 @@ metadata:
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -6,11 +6,13 @@ metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Enable public web traffic for the component without creating a Service.
|
||||
labels:
|
||||
custom.definition.oam.dev/deprecated: "true"
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: pure-ingress
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads: []
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
conflictsWith: []
|
||||
podDisruptive: false
|
||||
schematic:
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/register-grafana-datasource.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add a datasource to Grafana
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: register-grafana-datasource
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads: []
|
||||
conflictsWith: []
|
||||
podDisruptive: false
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
outputs: registerdatasource: {
|
||||
apiVersion: "grafana.extension.oam.dev/v1alpha1"
|
||||
kind: "DatasourceRegistration"
|
||||
spec: {
|
||||
grafana: {
|
||||
service: parameter.grafanaServiceName
|
||||
namespace: parameter.grafanaServiceNamespace
|
||||
credentialSecret: parameter.credentialSecret
|
||||
credentialSecretNamespace: parameter.credentialSecretNamespace
|
||||
}
|
||||
datasource: {
|
||||
name: parameter.name
|
||||
type: parameter.type
|
||||
access: parameter.access
|
||||
service: parameter.service
|
||||
namespace: parameter.namespace
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
grafanaServiceName: string
|
||||
grafanaServiceNamespace: *"default" | string
|
||||
credentialSecret: string
|
||||
credentialSecretNamespace: string
|
||||
name: string
|
||||
type: string
|
||||
access: *"proxy" | string
|
||||
service: string
|
||||
namespace: *"default" | string
|
||||
}
|
||||
workloadRefPath: ""
|
||||
|
||||
@@ -5,13 +5,14 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add resource requests and limits on K8s pod for your workload which follows the pod spec in path 'spec.template.'
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: resource
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -9,7 +9,8 @@ metadata:
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
podDisruptive: false
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -9,7 +9,10 @@ metadata:
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: false
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -11,7 +11,10 @@ metadata:
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/shared-resource.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: PolicyDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Configure the resources to be sharable across applications.
|
||||
name: shared-resource
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
#SharedResourcePolicyRule: {
|
||||
// +usage=Specify how to select the targets of the rule
|
||||
selector: [...#ResourcePolicyRuleSelector]
|
||||
}
|
||||
#ResourcePolicyRuleSelector: {
|
||||
// +usage=Select resources by component names
|
||||
componentNames?: [...string]
|
||||
// +usage=Select resources by component types
|
||||
componentTypes?: [...string]
|
||||
// +usage=Select resources by oamTypes (COMPONENT or TRAIT)
|
||||
oamTypes?: [...string]
|
||||
// +usage=Select resources by trait types
|
||||
traitTypes?: [...string]
|
||||
// +usage=Select resources by resource types (like Deployment)
|
||||
resourceTypes?: [...string]
|
||||
// +usage=Select resources by their names
|
||||
resourceNames?: [...string]
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Specify the list of rules to control shared-resource strategy at resource level.
|
||||
// The selected resource will be sharable across applications. (That means multiple applications
|
||||
// can all read it without conflict, but only the first one can write it)
|
||||
rules?: [...#SharedResourcePolicyRule]
|
||||
}
|
||||
|
||||
@@ -5,13 +5,14 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Inject a sidecar container to K8s pod for your workload which follows the pod spec in path 'spec.template'.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: sidecar
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -10,6 +10,9 @@ metadata:
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
77
charts/vela-core/templates/velaql/component-pod.yaml
Normal file
77
charts/vela-core/templates/velaql/component-pod.yaml
Normal file
@@ -0,0 +1,77 @@
|
||||
{{- if not (lookup "v1" "ConfigMap" (include "systemDefinitionNamespace" .) "component-pod-view") }}
|
||||
apiVersion: v1
|
||||
data:
|
||||
template: |
|
||||
import (
|
||||
"vela/ql"
|
||||
)
|
||||
|
||||
parameter: {
|
||||
appName: string
|
||||
appNs: string
|
||||
name?: string
|
||||
cluster?: string
|
||||
clusterNs?: string
|
||||
}
|
||||
|
||||
result: ql.#CollectPods & {
|
||||
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 result.err == _|_ {
|
||||
status: {
|
||||
podList: [ for pod in result.list if pod.object != _|_ {
|
||||
cluster: pod.cluster
|
||||
workload: pod.workload
|
||||
component: pod.component
|
||||
metadata: {
|
||||
name: pod.object.metadata.name
|
||||
namespace: pod.object.metadata.namespace
|
||||
creationTime: pod.object.metadata.creationTimestamp
|
||||
labels: pod.object.metadata.labels
|
||||
version: {
|
||||
if pod.publishVersion != _|_ {
|
||||
publishVersion: pod.publishVersion
|
||||
}
|
||||
if pod.deployVersion != _|_ {
|
||||
deployVersion: pod.deployVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
status: {
|
||||
phase: pod.object.status.phase
|
||||
// refer to https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
|
||||
if phase != "Pending" && phase != "Unknown" {
|
||||
podIP: pod.object.status.podIP
|
||||
hostIP: pod.object.status.hostIP
|
||||
nodeName: pod.object.spec.nodeName
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
if result.err != _|_ {
|
||||
status: {
|
||||
error: result.err
|
||||
}
|
||||
}
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: component-pod-view
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
{{- end }}
|
||||
50
charts/vela-core/templates/velaql/component-service.yaml
Normal file
50
charts/vela-core/templates/velaql/component-service.yaml
Normal file
@@ -0,0 +1,50 @@
|
||||
{{- if not (lookup "v1" "ConfigMap" (include "systemDefinitionNamespace" .) "component-service-view") }}
|
||||
apiVersion: v1
|
||||
data:
|
||||
template: |
|
||||
import (
|
||||
"vela/ql"
|
||||
)
|
||||
|
||||
parameter: {
|
||||
appName: string
|
||||
appNs: string
|
||||
name?: string
|
||||
cluster?: string
|
||||
clusterNs?: string
|
||||
}
|
||||
|
||||
result: ql.#CollectServices & {
|
||||
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 result.err == _|_ {
|
||||
status: {
|
||||
services: result.list
|
||||
}
|
||||
}
|
||||
|
||||
if result.err != _|_ {
|
||||
status: {
|
||||
error: result.err
|
||||
}
|
||||
}
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: component-service-view
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
{{- end}}
|
||||
@@ -3650,7 +3650,7 @@ spec:
|
||||
appliesToWorkloads:
|
||||
description: AppliesToWorkloads specifies the list of workload
|
||||
kinds this trait applies to. Workload kinds are specified
|
||||
in kind.group/version format, e.g. server.core.oam.dev/v1alpha2.
|
||||
in resource.group/version format, e.g. server.core.oam.dev/v1alpha2.
|
||||
Traits that omit this field apply to all workload kinds.
|
||||
items:
|
||||
type: string
|
||||
|
||||
@@ -708,7 +708,7 @@ spec:
|
||||
appliesToWorkloads:
|
||||
description: AppliesToWorkloads specifies the list of workload
|
||||
kinds this trait applies to. Workload kinds are specified
|
||||
in kind.group/version format, e.g. server.core.oam.dev/v1alpha2.
|
||||
in resource.group/version format, e.g. server.core.oam.dev/v1alpha2.
|
||||
Traits that omit this field apply to all workload kinds.
|
||||
items:
|
||||
type: string
|
||||
|
||||
@@ -105,6 +105,9 @@ spec:
|
||||
description: 'Specific resourceVersion to which this reference
|
||||
is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
|
||||
type: string
|
||||
skipGC:
|
||||
description: SkipGC marks the resource to skip gc
|
||||
type: boolean
|
||||
trait:
|
||||
type: string
|
||||
uid:
|
||||
|
||||
@@ -356,7 +356,7 @@ spec:
|
||||
properties:
|
||||
appliesToWorkloads:
|
||||
description: AppliesToWorkloads specifies the list of workload kinds
|
||||
this trait applies to. Workload kinds are specified in kind.group/version
|
||||
this trait applies to. Workload kinds are specified in resource.group/version
|
||||
format, e.g. server.core.oam.dev/v1alpha2. Traits that omit this
|
||||
field apply to all workload kinds.
|
||||
items:
|
||||
|
||||
@@ -11,7 +11,10 @@ metadata:
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -4,9 +4,7 @@ apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add annotations on K8s pod for your workload which follows the pod spec in path 'spec.template'.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
definition.oam.dev/description: Add annotations on your workload. if it generates pod, add same annotations for generated pods.
|
||||
name: annotations
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -5,13 +5,14 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add command on K8s pod for your workload which follows the pod spec in path 'spec.template'
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: command
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
|
||||
@@ -5,13 +5,14 @@ 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:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -5,13 +5,12 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Automatically scale the component based on CPU usage.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: cpuscaler
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
|
||||
@@ -5,13 +5,14 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add env on K8s pod for your workload which follows the pod spec in path 'spec.template'
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: env
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
|
||||
@@ -5,11 +5,12 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Expose port to enable web traffic for your component.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: expose
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
podDisruptive: false
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -9,7 +9,8 @@ metadata:
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
podDisruptive: false
|
||||
schematic:
|
||||
cue:
|
||||
@@ -85,7 +86,7 @@ spec:
|
||||
// +usage=Set ingress class in '.spec.ingressClassName' instead of 'kubernetes.io/ingress.class' annotation.
|
||||
classInSpec: *false | bool
|
||||
|
||||
// +usage=Specify the secret name you want to quote.
|
||||
// +usage=Specify the secret name you want to quote to use tls.
|
||||
secretName?: string
|
||||
|
||||
// +usage=Specify the host of the ingress gateway, which is used to generate the endpoints when the host is empty.
|
||||
|
||||
@@ -5,13 +5,14 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add host aliases on K8s pod for your workload which follows the pod spec in path 'spec.template'.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: hostalias
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: false
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -5,13 +5,14 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: add an init container and use shared volume with pod
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: init-container
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -4,9 +4,7 @@ apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add labels on K8s pod for your workload which follows the pod spec in path 'spec.template'.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
definition.oam.dev/description: Add labels on your workload. if it generates pod, add same label for generated pods.
|
||||
name: labels
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
|
||||
@@ -5,13 +5,14 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add lifecycle hooks for every container of K8s pod for your workload which follows the pod spec in path 'spec.template'.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: lifecycle
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -11,7 +11,10 @@ metadata:
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -6,11 +6,13 @@ metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Enable public web traffic for the component without creating a Service.
|
||||
labels:
|
||||
custom.definition.oam.dev/deprecated: "true"
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: pure-ingress
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads: []
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
conflictsWith: []
|
||||
podDisruptive: false
|
||||
schematic:
|
||||
|
||||
@@ -6,6 +6,7 @@ metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add a datasource to Grafana
|
||||
labels:
|
||||
custom.definition.oam.dev/deprecated: "true"
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: register-grafana-datasource
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
|
||||
@@ -5,13 +5,14 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add resource requests and limits on K8s pod for your workload which follows the pod spec in path 'spec.template.'
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: resource
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -9,7 +9,8 @@ metadata:
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
podDisruptive: false
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -9,7 +9,10 @@ metadata:
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: false
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -11,7 +11,10 @@ metadata:
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/shared-resource.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: PolicyDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Configure the resources to be sharable across applications.
|
||||
name: shared-resource
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
#SharedResourcePolicyRule: {
|
||||
// +usage=Specify how to select the targets of the rule
|
||||
selector: [...#ResourcePolicyRuleSelector]
|
||||
}
|
||||
#ResourcePolicyRuleSelector: {
|
||||
// +usage=Select resources by component names
|
||||
componentNames?: [...string]
|
||||
// +usage=Select resources by component types
|
||||
componentTypes?: [...string]
|
||||
// +usage=Select resources by oamTypes (COMPONENT or TRAIT)
|
||||
oamTypes?: [...string]
|
||||
// +usage=Select resources by trait types
|
||||
traitTypes?: [...string]
|
||||
// +usage=Select resources by resource types (like Deployment)
|
||||
resourceTypes?: [...string]
|
||||
// +usage=Select resources by their names
|
||||
resourceNames?: [...string]
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Specify the list of rules to control shared-resource strategy at resource level.
|
||||
// The selected resource will be sharable across applications. (That means multiple applications
|
||||
// can all read it without conflict, but only the first one can write it)
|
||||
rules?: [...#SharedResourcePolicyRule]
|
||||
}
|
||||
|
||||
@@ -5,13 +5,14 @@ kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Inject a sidecar container to K8s pod for your workload which follows the pod spec in path 'spec.template'.
|
||||
labels:
|
||||
custom.definition.oam.dev/ui-hidden: "true"
|
||||
name: sidecar
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- '*'
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -10,6 +10,9 @@ metadata:
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"time"
|
||||
|
||||
restfulspec "github.com/emicklei/go-restful-openapi/v2"
|
||||
"github.com/fatih/color"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/google/uuid"
|
||||
flag "github.com/spf13/pflag"
|
||||
@@ -82,6 +83,10 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
// The server is not terminal, there is no color default.
|
||||
// Force set to false, this is useful for the dry-run API.
|
||||
color.NoColor = false
|
||||
|
||||
errChan := make(chan error)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
@@ -19,6 +19,7 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
goflag "flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -139,6 +140,7 @@ func main() {
|
||||
flag.DurationVar(&clusterMetricsInterval, "cluster-metrics-interval", 15*time.Second, "The interval that ClusterMetricsMgr will collect metrics from clusters, default value is 15 seconds.")
|
||||
flag.BoolVar(&controllerArgs.EnableCompatibility, "enable-asi-compatibility", false, "enable compatibility for asi")
|
||||
flag.BoolVar(&controllerArgs.IgnoreAppWithoutControllerRequirement, "ignore-app-without-controller-version", false, "If true, application controller will not process the app without 'app.oam.dev/controller-version-require' annotation")
|
||||
flag.BoolVar(&controllerArgs.IgnoreDefinitionWithoutControllerRequirement, "ignore-definition-without-controller-version", false, "If true, trait/component/workflowstep definition controller will not process the definition without 'definition.oam.dev/controller-version-require' annotation")
|
||||
standardcontroller.AddOptimizeFlags()
|
||||
standardcontroller.AddAdmissionFlags()
|
||||
flag.IntVar(&resourcekeeper.MaxDispatchConcurrent, "max-dispatch-concurrent", 10, "Set the max dispatch concurrent number, default is 10")
|
||||
@@ -147,9 +149,10 @@ func main() {
|
||||
flag.IntVar(&wfTypes.MaxWorkflowStepErrorRetryTimes, "max-workflow-step-error-retry-times", 10, "Set the max workflow step error retry times, default is 10")
|
||||
utilfeature.DefaultMutableFeatureGate.AddFlag(flag.CommandLine)
|
||||
|
||||
flag.Parse()
|
||||
// setup logging
|
||||
klog.InitFlags(nil)
|
||||
flag.CommandLine.AddGoFlagSet(goflag.CommandLine)
|
||||
flag.Parse()
|
||||
if logDebug {
|
||||
_ = flag.Set("v", strconv.Itoa(int(commonconfig.LogDebug)))
|
||||
}
|
||||
|
||||
50
e2e/addon/mock/testdata/mock-addon/definitions/json-patch.cue
vendored
Normal file
50
e2e/addon/mock/testdata/mock-addon/definitions/json-patch.cue
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
"kustomize-json-patch-mock-adddon": {
|
||||
attributes: {
|
||||
podDisruptive: false
|
||||
}
|
||||
description: "A list of JSON6902 patch to selected target"
|
||||
labels: {
|
||||
"ui-hidden": "true"
|
||||
}
|
||||
type: "trait"
|
||||
}
|
||||
|
||||
template: {
|
||||
patch: {
|
||||
spec: {
|
||||
patches: parameter.patchesJson
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=A list of JSON6902 patch.
|
||||
patchesJson: [...#jsonPatchItem]
|
||||
}
|
||||
|
||||
// +usage=Contains a JSON6902 patch
|
||||
#jsonPatchItem: {
|
||||
target: #selector
|
||||
patch: [...{
|
||||
// +usage=operation to perform
|
||||
op: string | "add" | "remove" | "replace" | "move" | "copy" | "test"
|
||||
// +usage=operate path e.g. /foo/bar
|
||||
path: string
|
||||
// +usage=specify source path when op is copy/move
|
||||
from?: string
|
||||
// +usage=specify opraation value when op is test/add/replace
|
||||
value?: string
|
||||
}]
|
||||
}
|
||||
|
||||
// +usage=Selector specifies a set of resources
|
||||
#selector: {
|
||||
group?: string
|
||||
version?: string
|
||||
kind?: string
|
||||
namespace?: string
|
||||
name?: string
|
||||
annotationSelector?: string
|
||||
labelSelector?: string
|
||||
}
|
||||
|
||||
}
|
||||
1
e2e/addon/mock/testdata/mock-addon/readme.md
vendored
Normal file
1
e2e/addon/mock/testdata/mock-addon/readme.md
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Test addon readme.md file
|
||||
@@ -80,11 +80,15 @@ func ApplyMockServerConfig() error {
|
||||
}
|
||||
}
|
||||
if err := k8sClient.Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-vela"}}); err != nil {
|
||||
return err
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
otherRegistry.SetNamespace("test-vela")
|
||||
if err := k8sClient.Create(ctx, otherRegistry); err != nil {
|
||||
return err
|
||||
if !apierrors.IsAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ var (
|
||||
func main() {
|
||||
err := utils.ApplyMockServerConfig()
|
||||
if err != nil {
|
||||
log.Fatal("Apply mock server config to ConfigMap fail")
|
||||
log.Fatal(err)
|
||||
}
|
||||
http.HandleFunc("/", ossHandler)
|
||||
http.HandleFunc("/helm/", helmHandler)
|
||||
|
||||
@@ -42,10 +42,10 @@ var (
|
||||
applicationName = "app-basic"
|
||||
traitAlias = "scaler"
|
||||
appNameForInit = "initmyapp"
|
||||
jsonAppFile = `{"name":"nginx-vela","services":{"nginx":{"type":"webservice","image":"nginx:1.9.4","port":80}}}`
|
||||
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}}}}`
|
||||
jsonAppFile = `{"name":"nginx-vela","services":{"nginx":{"type":"webservice","image":"nginx:1.9.4","ports":[{port: 80, expose: true}]}}}`
|
||||
testDeleteJsonAppFile = `{"name":"test-vela-delete","services":{"nginx-test":{"type":"webservice","image":"nginx:1.9.4","ports":[{port: 80, expose: true}]}}}`
|
||||
appbasicJsonAppFile = `{"name":"app-basic","services":{"app-basic":{"type":"webservice","image":"nginx:1.9.4","ports":[{port: 80, expose: true}]}}}`
|
||||
appbasicAddTraitJsonAppFile = `{"name":"app-basic","services":{"app-basic":{"type":"webservice","image":"nginx:1.9.4","ports":[{port: 80, expose: true}],"scaler":{"replicas":2}}}}`
|
||||
velaQL = "test-component-pod-view{appNs=default,appName=nginx-vela,name=nginx}"
|
||||
)
|
||||
|
||||
@@ -303,7 +303,7 @@ var VelaQLPodListContext = func(context string, velaQL string) bool {
|
||||
gomega.Expect(v.Workload.ApiVersion).To(gomega.ContainSubstring("apps/v1"))
|
||||
}
|
||||
if v.Workload.Kind != "" {
|
||||
gomega.Expect(v.Workload.Kind).To(gomega.ContainSubstring("Deployment"))
|
||||
gomega.Expect(v.Workload.Kind).To(gomega.ContainSubstring("ReplicaSet"))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -7,7 +7,6 @@ data:
|
||||
template: |
|
||||
import (
|
||||
"vela/ql"
|
||||
"vela/op"
|
||||
)
|
||||
|
||||
parameter: {
|
||||
@@ -18,7 +17,7 @@ data:
|
||||
clusterNs?: string
|
||||
}
|
||||
|
||||
application: ql.#ListResourcesInApp & {
|
||||
result: ql.#CollectPods & {
|
||||
app: {
|
||||
name: parameter.appName
|
||||
namespace: parameter.appNs
|
||||
@@ -36,63 +35,41 @@ data:
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if result.err == _|_ {
|
||||
status: {
|
||||
podList: [ for podInfo in podStatus {
|
||||
name: podInfo.name
|
||||
containers: [ for containerName, container in podInfo.containers {
|
||||
containerName
|
||||
}]
|
||||
events: podInfo.events.list
|
||||
podList: [ for pod in result.list if pod.object != _|_ {
|
||||
cluster: pod.cluster
|
||||
workload: pod.workload
|
||||
component: pod.component
|
||||
metadata: {
|
||||
name: pod.object.metadata.name
|
||||
namespace: pod.object.metadata.namespace
|
||||
creationTime: pod.object.metadata.creationTimestamp
|
||||
labels: pod.object.metadata.labels
|
||||
version: {
|
||||
if pod.publishVersion != _|_ {
|
||||
publishVersion: pod.publishVersion
|
||||
}
|
||||
if pod.deployVersion != _|_ {
|
||||
deployVersion: pod.deployVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
status: {
|
||||
phase: pod.object.status.phase
|
||||
// refer to https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
|
||||
if phase != "Pending" && phase != "Unknown" {
|
||||
podIP: pod.object.status.podIP
|
||||
hostIP: pod.object.status.hostIP
|
||||
nodeName: pod.object.spec.nodeName
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
if result.err != _|_ {
|
||||
status: {
|
||||
error: result.err
|
||||
}
|
||||
}
|
||||
|
||||
3
go.mod
3
go.mod
@@ -124,6 +124,8 @@ require (
|
||||
sigs.k8s.io/gateway-api v0.4.3
|
||||
)
|
||||
|
||||
require github.com/rogpeppe/go-internal v1.8.0
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.7.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
@@ -256,7 +258,6 @@ require (
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.28.0 // indirect
|
||||
github.com/prometheus/procfs v0.6.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.8.0 // indirect
|
||||
github.com/rubenv/sql-migrate v0.0.0-20210614095031-55d5740dbbcc // indirect
|
||||
github.com/russross/blackfriday v1.6.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
|
||||
@@ -86,7 +86,9 @@ func TraitDef(ctx context.Context, c common.Args, path, location *string, defdir
|
||||
},
|
||||
CustomDocHeader: CustomTraitHeaderEN,
|
||||
}
|
||||
ref.Remote = &docgen.FromCluster{Namespace: types.DefaultKubeVelaNS}
|
||||
ref.Local = &docgen.FromLocal{
|
||||
Path: TraitDefDir,
|
||||
}
|
||||
|
||||
if *path != "" {
|
||||
ref.I18N = &docgen.En
|
||||
@@ -99,22 +101,24 @@ func TraitDef(ctx context.Context, c common.Args, path, location *string, defdir
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), *path)
|
||||
}
|
||||
if *location == "" || *location == "en" {
|
||||
ref.I18N = &docgen.En
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, TraitDefRefPath); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
} else {
|
||||
// Generate to default path depends on language
|
||||
if *location == "" || *location == "en" {
|
||||
ref.I18N = &docgen.En
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, TraitDefRefPath); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), TraitDefRefPath)
|
||||
}
|
||||
fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), TraitDefRefPath)
|
||||
}
|
||||
if *location == "" || *location == "zh" {
|
||||
ref.I18N = &docgen.Zh
|
||||
ref.CustomDocHeader = CustomTraitHeaderZH
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, TraitDefRefPathZh); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
if *location == "" || *location == "zh" {
|
||||
ref.I18N = &docgen.Zh
|
||||
ref.CustomDocHeader = CustomTraitHeaderZH
|
||||
if err := ref.GenerateReferenceDocs(ctx, c, TraitDefRefPathZh); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), TraitDefRefPathZh)
|
||||
}
|
||||
fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), TraitDefRefPathZh)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3650,7 +3650,7 @@ spec:
|
||||
appliesToWorkloads:
|
||||
description: AppliesToWorkloads specifies the list of workload
|
||||
kinds this trait applies to. Workload kinds are specified
|
||||
in kind.group/version format, e.g. server.core.oam.dev/v1alpha2.
|
||||
in resource.group/version format, e.g. server.core.oam.dev/v1alpha2.
|
||||
Traits that omit this field apply to all workload kinds.
|
||||
items:
|
||||
type: string
|
||||
|
||||
@@ -708,7 +708,7 @@ spec:
|
||||
appliesToWorkloads:
|
||||
description: AppliesToWorkloads specifies the list of workload
|
||||
kinds this trait applies to. Workload kinds are specified
|
||||
in kind.group/version format, e.g. server.core.oam.dev/v1alpha2.
|
||||
in resource.group/version format, e.g. server.core.oam.dev/v1alpha2.
|
||||
Traits that omit this field apply to all workload kinds.
|
||||
items:
|
||||
type: string
|
||||
|
||||
@@ -105,6 +105,9 @@ spec:
|
||||
description: 'Specific resourceVersion to which this reference
|
||||
is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
|
||||
type: string
|
||||
skipGC:
|
||||
description: SkipGC marks the resource to skip gc
|
||||
type: boolean
|
||||
trait:
|
||||
type: string
|
||||
uid:
|
||||
|
||||
@@ -356,7 +356,7 @@ spec:
|
||||
properties:
|
||||
appliesToWorkloads:
|
||||
description: AppliesToWorkloads specifies the list of workload kinds
|
||||
this trait applies to. Workload kinds are specified in kind.group/version
|
||||
this trait applies to. Workload kinds are specified in resource.group/version
|
||||
format, e.g. server.core.oam.dev/v1alpha2. Traits that omit this
|
||||
field apply to all workload kinds.
|
||||
items:
|
||||
|
||||
@@ -8,7 +8,8 @@ e2e-setup-core-post-hook:
|
||||
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
|
||||
bin/vela addon enable ./e2e/addon/mock/testdata/fluxcd
|
||||
bin/vela addon enable ./e2e/addon/mock/testdata/rollout
|
||||
|
||||
.PHONY: e2e-setup-core-wo-auth
|
||||
e2e-setup-core-wo-auth:
|
||||
@@ -37,10 +38,10 @@ e2e-setup:
|
||||
|
||||
go run ./e2e/addon/mock &
|
||||
sleep 15
|
||||
bin/vela addon enable fluxcd
|
||||
bin/vela addon enable terraform
|
||||
bin/vela addon enable terraform-alibaba ALICLOUD_ACCESS_KEY=xxx ALICLOUD_SECRET_KEY=yyy ALICLOUD_REGION=cn-beijing
|
||||
bin/vela addon enable rollout
|
||||
bin/vela addon enable ./e2e/addon/mock/testdata/fluxcd
|
||||
bin/vela addon enable ./e2e/addon/mock/testdata/terraform
|
||||
bin/vela addon enable ./e2e/addon/mock/testdata/terraform-alibaba ALICLOUD_ACCESS_KEY=xxx ALICLOUD_SECRET_KEY=yyy ALICLOUD_REGION=cn-beijing
|
||||
bin/vela addon enable ./e2e/addon/mock/testdata/rollout
|
||||
ginkgo version
|
||||
ginkgo -v -r e2e/setup
|
||||
|
||||
|
||||
@@ -79,6 +79,9 @@ const (
|
||||
// ReadmeFileName is the addon readme file name
|
||||
ReadmeFileName string = "README.md"
|
||||
|
||||
// LegacyReadmeFileName is the addon readme lower case file name
|
||||
LegacyReadmeFileName string = "readme.md"
|
||||
|
||||
// MetadataFileName is the addon meatadata.yaml file name
|
||||
MetadataFileName string = "metadata.yaml"
|
||||
|
||||
@@ -205,7 +208,7 @@ type Pattern struct {
|
||||
var Patterns = []Pattern{
|
||||
{Value: ReadmeFileName}, {Value: MetadataFileName}, {Value: TemplateFileName},
|
||||
{Value: ParameterFileName}, {IsDir: true, Value: ResourcesDirName}, {IsDir: true, Value: DefinitionsDirName},
|
||||
{IsDir: true, Value: DefSchemaName}, {IsDir: true, Value: ViewDirName}, {Value: AppTemplateCueFileName}, {Value: GlobalParameterFileName}}
|
||||
{IsDir: true, Value: DefSchemaName}, {IsDir: true, Value: ViewDirName}, {Value: AppTemplateCueFileName}, {Value: GlobalParameterFileName}, {Value: LegacyReadmeFileName}}
|
||||
|
||||
// GetPatternFromItem will check if the file path has a valid pattern, return empty string if it's invalid.
|
||||
// AsyncReader is needed to calculate relative path
|
||||
@@ -285,6 +288,7 @@ func GetUIDataFromReader(r AsyncReader, meta *SourceMeta, opt ListOptions) (*UID
|
||||
read func(a *UIData, reader AsyncReader, readPath string) error
|
||||
}{
|
||||
ReadmeFileName: {!opt.GetDetail, readReadme},
|
||||
LegacyReadmeFileName: {!opt.GetDetail, readReadme},
|
||||
MetadataFileName: {false, readMetadata},
|
||||
DefinitionsDirName: {!opt.GetDefinition, readDefFile},
|
||||
ParameterFileName: {!opt.GetParameter, readParamFile},
|
||||
@@ -481,6 +485,10 @@ func readMetadata(a *UIData, reader AsyncReader, readPath string) error {
|
||||
}
|
||||
|
||||
func readReadme(a *UIData, reader AsyncReader, readPath string) error {
|
||||
// the detail will contain readme.md or README.md, if the content already is filled, don't read another.
|
||||
if len(a.Detail) != 0 {
|
||||
return nil
|
||||
}
|
||||
content, err := reader.ReadFile(readPath)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -675,7 +683,7 @@ func RenderDefinitions(addon *InstallPackage, config *rest.Config) ([]*unstructu
|
||||
for _, def := range addon.Definitions {
|
||||
obj, err := renderObject(def)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "render definition file %s", def.Name)
|
||||
}
|
||||
// we should ignore the namespace defined in definition yaml, override the filed by DefaultKubeVelaNS
|
||||
obj.SetNamespace(types.DefaultKubeVelaNS)
|
||||
@@ -704,7 +712,7 @@ func RenderDefinitionSchema(addon *InstallPackage) ([]*unstructured.Unstructured
|
||||
for _, teml := range addon.DefSchemas {
|
||||
u, err := renderSchemaConfigmap(teml)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "render uiSchema file %s", teml.Name)
|
||||
}
|
||||
schemaConfigmaps = append(schemaConfigmaps, u)
|
||||
}
|
||||
@@ -717,14 +725,14 @@ func RenderViews(addon *InstallPackage) ([]*unstructured.Unstructured, error) {
|
||||
for _, view := range addon.YAMLViews {
|
||||
obj, err := renderObject(view)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "render velaQL view file %s", view.Name)
|
||||
}
|
||||
views = append(views, obj)
|
||||
}
|
||||
for _, view := range addon.CUEViews {
|
||||
obj, err := renderCUEView(view)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "render velaQL view file %s", view.Name)
|
||||
}
|
||||
views = append(views, obj)
|
||||
}
|
||||
@@ -788,7 +796,7 @@ func renderK8sObjectsComponent(elems []ElementFile, addonName string) (*common2.
|
||||
for _, elem := range elems {
|
||||
obj, err := renderObject(elem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "render resource file %s", elem.Name)
|
||||
}
|
||||
objects = append(objects, obj)
|
||||
}
|
||||
@@ -889,6 +897,7 @@ type Installer struct {
|
||||
cache *Cache
|
||||
dc *discovery.DiscoveryClient
|
||||
skipVersionValidate bool
|
||||
overrideDefs bool
|
||||
}
|
||||
|
||||
// NewAddonInstaller will create an installer for addon
|
||||
@@ -985,12 +994,8 @@ func (h *Installer) getAddonMeta() (map[string]SourceMeta, error) {
|
||||
|
||||
// installDependency checks if addon's dependency and install it
|
||||
func (h *Installer) installDependency(addon *InstallPackage) error {
|
||||
var app v1beta1.Application
|
||||
for _, dep := range addon.Dependencies {
|
||||
err := h.cli.Get(h.ctx, client.ObjectKey{
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Name: addonutil.Addon2AppName(dep.Name),
|
||||
}, &app)
|
||||
_, err := FetchAddonRelatedApp(h.ctx, h.cli, dep.Name)
|
||||
if err == nil {
|
||||
continue
|
||||
}
|
||||
@@ -1052,7 +1057,7 @@ func (h *Installer) createOrUpdate(app *v1beta1.Application) error {
|
||||
}
|
||||
|
||||
func (h *Installer) dispatchAddonResource(addon *InstallPackage) error {
|
||||
app, err := RenderApp(h.ctx, addon, h.cli, h.args)
|
||||
app, auxiliaryOutputs, err := RenderApp(h.ctx, addon, h.cli, h.args)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "render addon application fail")
|
||||
}
|
||||
@@ -1069,6 +1074,16 @@ func (h *Installer) dispatchAddonResource(addon *InstallPackage) error {
|
||||
return errors.Wrap(err, "render addon definitions fail")
|
||||
}
|
||||
|
||||
if !h.overrideDefs {
|
||||
existDefs, err := checkConflictDefs(h.ctx, h.cli, defs, app.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(existDefs) != 0 {
|
||||
return produceDefConflictError(existDefs)
|
||||
}
|
||||
}
|
||||
|
||||
schemas, err := RenderDefinitionSchema(addon)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "render addon definitions' schema fail")
|
||||
@@ -1083,17 +1098,15 @@ func (h *Installer) dispatchAddonResource(addon *InstallPackage) error {
|
||||
return errors.Wrapf(err, "cannot pass definition to addon app's annotation")
|
||||
}
|
||||
|
||||
var auxiliaryOutputs []*unstructured.Unstructured
|
||||
auxiliaryOutputs, err = renderOutputs(addon, h.args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = h.createOrUpdate(app); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, def := range defs {
|
||||
if !checkBondComponentExist(*def, *app) {
|
||||
continue
|
||||
}
|
||||
// if binding component exist, apply the definition
|
||||
addOwner(def, app)
|
||||
err = h.apply.Apply(h.ctx, def, apply.DisableUpdateAnnotation())
|
||||
if err != nil {
|
||||
@@ -1118,6 +1131,9 @@ func (h *Installer) dispatchAddonResource(addon *InstallPackage) error {
|
||||
}
|
||||
|
||||
for _, o := range auxiliaryOutputs {
|
||||
if !checkBondComponentExist(*o, *app) {
|
||||
continue
|
||||
}
|
||||
addOwner(o, app)
|
||||
err = h.apply.Apply(h.ctx, o, apply.DisableUpdateAnnotation())
|
||||
if err != nil {
|
||||
@@ -1292,26 +1308,30 @@ func checkSemVer(actual string, require string) (bool, error) {
|
||||
if len(require) == 0 {
|
||||
return true, nil
|
||||
}
|
||||
smeVer := strings.TrimPrefix(actual, "v")
|
||||
semVer := strings.TrimPrefix(actual, "v")
|
||||
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)
|
||||
v, err := semver.NewVersion(semVer)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to new version %s: %s", smeVer, err.Error())
|
||||
log.Logger.Errorf("fail to new version %s: %s", semVer, err.Error())
|
||||
return false, err
|
||||
}
|
||||
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)
|
||||
semVer := strings.TrimPrefix(actual[:strings.Index(actual, "-")], "v")
|
||||
if strings.Contains(require, ">=") && require[strings.Index(require, "=")+1:] == semVer {
|
||||
// for case: `actual` is 1.5.0-beta.1 require is >=`1.5.0`
|
||||
return false, nil
|
||||
}
|
||||
v, err := semver.NewVersion(semVer)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to new version %s: %s", smeVer, err.Error())
|
||||
log.Logger.Errorf("fail to new version %s: %s", semVer, err.Error())
|
||||
return false, err
|
||||
}
|
||||
if constraint.Check(v) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
types2 "k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
@@ -307,7 +308,7 @@ var _ = Describe("Test render addon with specified clusters", func() {
|
||||
args := map[string]interface{}{
|
||||
"clusters": []string{"add-c1", "ne"},
|
||||
}
|
||||
_, err := RenderApp(ctx, i, k8sClient, args)
|
||||
_, _, err := RenderApp(ctx, i, k8sClient, args)
|
||||
Expect(err.Error()).Should(BeEquivalentTo("cluster ne not exist"))
|
||||
})
|
||||
It("test render normal addon with specified clusters", func() {
|
||||
@@ -317,7 +318,7 @@ var _ = Describe("Test render addon with specified clusters", func() {
|
||||
args := map[string]interface{}{
|
||||
"clusters": []string{"add-c1", "add-c2"},
|
||||
}
|
||||
ap, err := RenderApp(ctx, i, k8sClient, args)
|
||||
ap, _, err := RenderApp(ctx, i, k8sClient, args)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(ap.Spec.Policies).Should(BeEquivalentTo([]v1beta1.AppPolicy{{Name: specifyAddonClustersTopologyPolicy,
|
||||
Type: v1alpha12.TopologyPolicyType,
|
||||
@@ -396,6 +397,60 @@ var _ = Describe("test enable addon which applies the views independently", func
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("test override defs of addon", func() {
|
||||
It("test compDef exist", func() {
|
||||
ctx := context.Background()
|
||||
comp := v1beta1.ComponentDefinition{TypeMeta: metav1.TypeMeta{APIVersion: v1beta1.SchemeGroupVersion.String(), Kind: v1beta1.ComponentDefinitionKind}}
|
||||
Expect(yaml.Unmarshal([]byte(helmCompDefYaml), &comp)).Should(BeNil())
|
||||
Expect(k8sClient.Create(ctx, &comp)).Should(BeNil())
|
||||
|
||||
comp2 := v1beta1.ComponentDefinition{TypeMeta: metav1.TypeMeta{APIVersion: v1beta1.SchemeGroupVersion.String(), Kind: v1beta1.ComponentDefinitionKind}}
|
||||
Expect(yaml.Unmarshal([]byte(kustomizeCompDefYaml), &comp2)).Should(BeNil())
|
||||
Expect(k8sClient.Create(ctx, &comp2)).Should(BeNil())
|
||||
app := v1beta1.Application{ObjectMeta: metav1.ObjectMeta{Name: "addon-fluxcd"}}
|
||||
|
||||
comp3 := v1beta1.ComponentDefinition{TypeMeta: metav1.TypeMeta{APIVersion: v1beta1.SchemeGroupVersion.String(), Kind: v1beta1.ComponentDefinitionKind}}
|
||||
Expect(yaml.Unmarshal([]byte(kustomizeCompDefYaml1), &comp3)).Should(BeNil())
|
||||
Expect(k8sClient.Create(ctx, &comp3)).Should(BeNil())
|
||||
|
||||
compUnstructured, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&comp)
|
||||
Expect(err).Should(BeNil())
|
||||
u := unstructured.Unstructured{Object: compUnstructured}
|
||||
u.SetAPIVersion(v1beta1.SchemeGroupVersion.String())
|
||||
u.SetKind(v1beta1.ComponentDefinitionKind)
|
||||
c, err := checkConflictDefs(ctx, k8sClient, []*unstructured.Unstructured{&u}, app.GetName())
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(c)).Should(BeEquivalentTo(1))
|
||||
|
||||
u.SetName("rollout")
|
||||
c, err = checkConflictDefs(ctx, k8sClient, []*unstructured.Unstructured{&u}, app.GetName())
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(c)).Should(BeEquivalentTo(0))
|
||||
|
||||
u.SetKind("NotExistKind")
|
||||
_, err = checkConflictDefs(ctx, k8sClient, []*unstructured.Unstructured{&u}, app.GetName())
|
||||
Expect(err).ShouldNot(BeNil())
|
||||
|
||||
compUnstructured2, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&comp2)
|
||||
Expect(err).Should(BeNil())
|
||||
u2 := &unstructured.Unstructured{Object: compUnstructured2}
|
||||
u2.SetAPIVersion(v1beta1.SchemeGroupVersion.String())
|
||||
u2.SetKind(v1beta1.ComponentDefinitionKind)
|
||||
c, err = checkConflictDefs(ctx, k8sClient, []*unstructured.Unstructured{u2}, app.GetName())
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(c)).Should(BeEquivalentTo(1))
|
||||
|
||||
compUnstructured3, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&comp3)
|
||||
Expect(err).Should(BeNil())
|
||||
u3 := &unstructured.Unstructured{Object: compUnstructured3}
|
||||
u3.SetAPIVersion(v1beta1.SchemeGroupVersion.String())
|
||||
u3.SetKind(v1beta1.ComponentDefinitionKind)
|
||||
c, err = checkConflictDefs(ctx, k8sClient, []*unstructured.Unstructured{u3}, app.GetName())
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(c)).Should(BeEquivalentTo(0))
|
||||
})
|
||||
})
|
||||
|
||||
const (
|
||||
appYaml = `apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
@@ -491,5 +546,49 @@ spec:
|
||||
properties:
|
||||
image: crccheck/hello-world
|
||||
port: 8000
|
||||
`
|
||||
helmCompDefYaml = `
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: helm
|
||||
namespace: vela-system
|
||||
ownerReferences:
|
||||
- apiVersion: core.oam.dev/v1beta1
|
||||
blockOwnerDeletion: true
|
||||
controller: true
|
||||
kind: Application
|
||||
name: addon-fluxcd-helm
|
||||
uid: 73c47933-002e-4182-a673-6da6a9dcf080
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
`
|
||||
kustomizeCompDefYaml = `
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: kustomize
|
||||
namespace: vela-system
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
`
|
||||
kustomizeCompDefYaml1 = `
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: kustomize-another
|
||||
namespace: vela-system
|
||||
ownerReferences:
|
||||
- apiVersion: core.oam.dev/v1beta1
|
||||
blockOwnerDeletion: true
|
||||
controller: true
|
||||
kind: Application
|
||||
name: addon-fluxcd
|
||||
uid: 73c47933-002e-4182-a673-6da6a9dcf080
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
`
|
||||
)
|
||||
|
||||
@@ -281,7 +281,7 @@ func TestRender(t *testing.T) {
|
||||
|
||||
func TestRenderApp(t *testing.T) {
|
||||
addon := baseAddon
|
||||
app, err := RenderApp(ctx, &addon, nil, map[string]interface{}{})
|
||||
app, _, err := RenderApp(ctx, &addon, nil, map[string]interface{}{})
|
||||
assert.NoError(t, err, "render app fail")
|
||||
// definition should not be rendered
|
||||
assert.Equal(t, len(app.Spec.Components), 1)
|
||||
@@ -290,7 +290,7 @@ func TestRenderApp(t *testing.T) {
|
||||
func TestRenderAppWithNeedNamespace(t *testing.T) {
|
||||
addon := baseAddon
|
||||
addon.NeedNamespace = append(addon.NeedNamespace, types.DefaultKubeVelaNS, "test-ns2")
|
||||
app, err := RenderApp(ctx, &addon, nil, map[string]interface{}{})
|
||||
app, _, err := RenderApp(ctx, &addon, nil, map[string]interface{}{})
|
||||
assert.NoError(t, err, "render app fail")
|
||||
assert.Equal(t, len(app.Spec.Components), 2)
|
||||
for _, c := range app.Spec.Components {
|
||||
@@ -311,7 +311,7 @@ func TestRenderDeploy2RuntimeAddon(t *testing.T) {
|
||||
assert.Equal(t, def.GetAPIVersion(), "core.oam.dev/v1beta1")
|
||||
assert.Equal(t, def.GetKind(), "TraitDefinition")
|
||||
|
||||
app, err := RenderApp(ctx, &addonDeployToRuntime, nil, map[string]interface{}{})
|
||||
app, _, err := RenderApp(ctx, &addonDeployToRuntime, nil, map[string]interface{}{})
|
||||
assert.NoError(t, err)
|
||||
policies := app.Spec.Policies
|
||||
assert.True(t, len(policies) == 1)
|
||||
@@ -331,7 +331,7 @@ func TestRenderDefinitions(t *testing.T) {
|
||||
assert.Equal(t, def.GetAPIVersion(), "core.oam.dev/v1beta1")
|
||||
assert.Equal(t, def.GetKind(), "TraitDefinition")
|
||||
|
||||
app, err := RenderApp(ctx, &addonDeployToRuntime, nil, map[string]interface{}{})
|
||||
app, _, err := RenderApp(ctx, &addonDeployToRuntime, nil, map[string]interface{}{})
|
||||
assert.NoError(t, err)
|
||||
// addon which app work on no-runtime-cluster mode workflow is nil
|
||||
assert.Nil(t, app.Spec.Workflow)
|
||||
@@ -368,7 +368,7 @@ func TestRenderK8sObjects(t *testing.T) {
|
||||
RuntimeCluster: false,
|
||||
}
|
||||
|
||||
app, err := RenderApp(ctx, &addonMultiYaml, nil, map[string]interface{}{})
|
||||
app, _, err := RenderApp(ctx, &addonMultiYaml, nil, map[string]interface{}{})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(app.Spec.Components), 1)
|
||||
comp := app.Spec.Components[0]
|
||||
@@ -945,6 +945,16 @@ func TestCheckSemVer(t *testing.T) {
|
||||
require: ">=v1.2.4-beta.3",
|
||||
res: false,
|
||||
},
|
||||
{
|
||||
actual: "1.5.0-beta.2",
|
||||
require: ">=1.5.0",
|
||||
res: false,
|
||||
},
|
||||
{
|
||||
actual: "1.5.0-alpha.2",
|
||||
require: ">=1.5.0",
|
||||
res: false,
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
result, err := checkSemVer(testCase.actual, testCase.require)
|
||||
@@ -1306,3 +1316,15 @@ func TestMergeAddonInstallArgs(t *testing.T) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGenerateConflictError(t *testing.T) {
|
||||
confictAddon := map[string]string{
|
||||
"helm": "definition: helm already exist and not belong to any addon \n",
|
||||
"kustomize": "definition: kustomize in this addon already exist in fluxcd \n",
|
||||
}
|
||||
err := produceDefConflictError(confictAddon)
|
||||
assert.Error(t, err)
|
||||
strings.Contains(err.Error(), "in this addon already exist in fluxcd")
|
||||
|
||||
assert.NoError(t, produceDefConflictError(map[string]string{}))
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ const (
|
||||
enabling = "enabling"
|
||||
// disabling indicates the addon related app is deleting
|
||||
disabling = "disabling"
|
||||
// suspend indicates the addon related app is suspend
|
||||
// suspend indicates the addon related app is suspended
|
||||
suspend = "suspend"
|
||||
)
|
||||
|
||||
|
||||
@@ -180,9 +180,7 @@ func (cmd *InitCmd) createRequiredFiles() {
|
||||
Description: "An addon for KubeVela.",
|
||||
Tags: []string{"my-tag"},
|
||||
Dependencies: []*Dependency{},
|
||||
DeployTo: &DeployTo{
|
||||
RuntimeCluster: false,
|
||||
},
|
||||
DeployTo: nil,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,7 +501,8 @@ parameter: {
|
||||
validate:
|
||||
required: true
|
||||
`
|
||||
appTemplate = `output: {
|
||||
appTemplate = `package main
|
||||
output: {
|
||||
apiVersion: "core.oam.dev/v1beta1"
|
||||
kind: "Application"
|
||||
spec: {
|
||||
|
||||
@@ -23,10 +23,12 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"cuelang.org/go/cue/parser"
|
||||
"github.com/pkg/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
common2 "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
@@ -37,6 +39,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/cue/model/value"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
addonutil "github.com/oam-dev/kubevela/pkg/utils/addon"
|
||||
)
|
||||
|
||||
@@ -103,46 +106,77 @@ func (a addonCueTemplateRender) toObject(cueTemplate string, path string, object
|
||||
}
|
||||
|
||||
// renderApp will render Application from CUE files
|
||||
func (a addonCueTemplateRender) renderApp() (*v1beta1.Application, error) {
|
||||
func (a addonCueTemplateRender) renderApp() (*v1beta1.Application, []*unstructured.Unstructured, error) {
|
||||
var app v1beta1.Application
|
||||
var outputs = map[string]interface{}{}
|
||||
var res []*unstructured.Unstructured
|
||||
|
||||
contextFile, err := a.formatContext()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "format context for app render")
|
||||
return nil, nil, errors.Wrap(err, "format context for app render")
|
||||
}
|
||||
contextCue, err := parser.ParseFile("parameter.cue", contextFile, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "parse parameter context")
|
||||
}
|
||||
if contextCue.PackageName() == "" {
|
||||
contextFile = value.DefaultPackageHeader + contextFile
|
||||
}
|
||||
|
||||
var files = []string{contextFile}
|
||||
for _, cuef := range a.addon.CUETemplates {
|
||||
files = append(files, cuef.Data)
|
||||
}
|
||||
|
||||
// TODO(wonderflow): add package discover to support vela own packages if needed
|
||||
v, err := value.NewValueWithFiles(a.addon.AppCueTemplate.Data, files, nil, "")
|
||||
v, err := value.NewValueWithMainAndFiles(a.addon.AppCueTemplate.Data, files, nil, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "load app template with CUE files")
|
||||
return nil, nil, errors.Wrap(err, "load app template with CUE files")
|
||||
}
|
||||
outputContent, err := v.LookupValue(renderOutputCuePath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "render app from output field from CUE")
|
||||
return nil, nil, errors.Wrap(err, "render app from output field from CUE")
|
||||
}
|
||||
err = outputContent.UnmarshalTo(&app)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "decode app from CUE")
|
||||
return nil, nil, errors.Wrap(err, "decode app from CUE")
|
||||
}
|
||||
return &app, nil
|
||||
auxiliaryContent, err := v.LookupValue(renderAuxiliaryOutputsPath)
|
||||
if err != nil {
|
||||
// no outputs defined in app template, return normal data
|
||||
if isErrorCueRenderPathNotFound(err, renderAuxiliaryOutputsPath) {
|
||||
return &app, res, nil
|
||||
}
|
||||
return nil, nil, errors.Wrap(err, "render app from output field from CUE")
|
||||
}
|
||||
|
||||
err = auxiliaryContent.UnmarshalTo(&outputs)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "decode app from CUE")
|
||||
}
|
||||
for k, o := range outputs {
|
||||
if ao, ok := o.(map[string]interface{}); ok {
|
||||
auxO := &unstructured.Unstructured{Object: ao}
|
||||
auxO.SetLabels(util.MergeMapOverrideWithDst(auxO.GetLabels(), map[string]string{oam.LabelAddonAuxiliaryName: k}))
|
||||
res = append(res, auxO)
|
||||
}
|
||||
}
|
||||
return &app, res, nil
|
||||
}
|
||||
|
||||
// generateAppFramework generate application from yaml defined by template.yaml or cue file from template.cue
|
||||
func generateAppFramework(addon *InstallPackage, parameters map[string]interface{}) (*v1beta1.Application, error) {
|
||||
func generateAppFramework(addon *InstallPackage, parameters map[string]interface{}) (*v1beta1.Application, []*unstructured.Unstructured, error) {
|
||||
if len(addon.AppCueTemplate.Data) != 0 && addon.AppTemplate != nil {
|
||||
return nil, ErrBothCueAndYamlTmpl
|
||||
return nil, nil, ErrBothCueAndYamlTmpl
|
||||
}
|
||||
|
||||
var app *v1beta1.Application
|
||||
var auxiliaryObjects []*unstructured.Unstructured
|
||||
var err error
|
||||
if len(addon.AppCueTemplate.Data) != 0 {
|
||||
app, err = renderAppAccordingToCueTemplate(addon, parameters)
|
||||
app, auxiliaryObjects, err = renderAppAccordingToCueTemplate(addon, parameters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
} else {
|
||||
app = addon.AppTemplate
|
||||
@@ -156,27 +190,36 @@ func generateAppFramework(addon *InstallPackage, parameters map[string]interface
|
||||
}
|
||||
}
|
||||
|
||||
app.Name = addonutil.Addon2AppName(addon.Name)
|
||||
// force override the namespace defined vela with DefaultVelaNS,this value can be modified by Env
|
||||
if app.Name != "" && app.Name != addonutil.Addon2AppName(addon.Name) {
|
||||
klog.Warningf("Application name %s will be overwritten with %s. Consider removing metadata.name in template.", app.Name, addonutil.Addon2AppName(addon.Name))
|
||||
}
|
||||
app.SetName(addonutil.Addon2AppName(addon.Name))
|
||||
|
||||
if app.Namespace != "" && app.Namespace != types.DefaultKubeVelaNS {
|
||||
klog.Warningf("Namespace %s will be overwritten with %s. Consider removing metadata.namespace in template.", app.Namespace, types.DefaultKubeVelaNS)
|
||||
}
|
||||
// force override the namespace defined vela with DefaultVelaNS. This value can be modified by env
|
||||
app.SetNamespace(types.DefaultKubeVelaNS)
|
||||
|
||||
if app.Labels == nil {
|
||||
app.Labels = make(map[string]string)
|
||||
}
|
||||
app.Labels[oam.LabelAddonName] = addon.Name
|
||||
app.Labels[oam.LabelAddonVersion] = addon.Version
|
||||
return app, nil
|
||||
|
||||
for _, aux := range auxiliaryObjects {
|
||||
aux.SetLabels(util.MergeMapOverrideWithDst(aux.GetLabels(), map[string]string{oam.LabelAddonName: addon.Name, oam.LabelAddonVersion: addon.Version}))
|
||||
}
|
||||
|
||||
return app, auxiliaryObjects, nil
|
||||
}
|
||||
|
||||
func renderAppAccordingToCueTemplate(addon *InstallPackage, args map[string]interface{}) (*v1beta1.Application, error) {
|
||||
func renderAppAccordingToCueTemplate(addon *InstallPackage, args map[string]interface{}) (*v1beta1.Application, []*unstructured.Unstructured, error) {
|
||||
r := addonCueTemplateRender{
|
||||
addon: addon,
|
||||
inputArgs: args,
|
||||
}
|
||||
app, err := r.renderApp()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return app, nil
|
||||
return r.renderApp()
|
||||
}
|
||||
|
||||
// renderCompAccordingCUETemplate will return a component from cue template
|
||||
@@ -199,19 +242,19 @@ func renderCompAccordingCUETemplate(cueTemplate ElementFile, addon *InstallPacka
|
||||
}
|
||||
|
||||
// RenderApp render a K8s application
|
||||
func RenderApp(ctx context.Context, addon *InstallPackage, k8sClient client.Client, args map[string]interface{}) (*v1beta1.Application, error) {
|
||||
func RenderApp(ctx context.Context, addon *InstallPackage, k8sClient client.Client, args map[string]interface{}) (*v1beta1.Application, []*unstructured.Unstructured, error) {
|
||||
if args == nil {
|
||||
args = map[string]interface{}{}
|
||||
}
|
||||
app, err := generateAppFramework(addon, args)
|
||||
app, auxiliaryObjects, err := generateAppFramework(addon, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
app.Spec.Components = append(app.Spec.Components, renderNeededNamespaceAsComps(addon)...)
|
||||
|
||||
resources, err := renderResources(addon, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
app.Spec.Components = append(app.Spec.Components, resources...)
|
||||
|
||||
@@ -219,10 +262,10 @@ func RenderApp(ctx context.Context, addon *InstallPackage, k8sClient client.Clie
|
||||
// attach topology policy to application.
|
||||
if checkNeedAttachTopologyPolicy(app, addon) {
|
||||
if err := attachPolicyForLegacyAddon(ctx, app, addon, args, k8sClient); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
return app, nil
|
||||
return app, auxiliaryObjects, nil
|
||||
}
|
||||
|
||||
func attachPolicyForLegacyAddon(ctx context.Context, app *v1beta1.Application, addon *InstallPackage, args map[string]interface{}, k8sClient client.Client) error {
|
||||
@@ -285,7 +328,7 @@ func renderResources(addon *InstallPackage, args map[string]interface{}) ([]comm
|
||||
if len(addon.YAMLTemplates) != 0 {
|
||||
comp, err := renderK8sObjectsComponent(addon.YAMLTemplates, addon.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "render components from yaml template")
|
||||
}
|
||||
resources = append(resources, *comp)
|
||||
}
|
||||
@@ -311,33 +354,13 @@ func checkNeedAttachTopologyPolicy(app *v1beta1.Application, addon *InstallPacka
|
||||
}
|
||||
for _, policy := range app.Spec.Policies {
|
||||
if policy.Type == v1alpha1.TopologyPolicyType {
|
||||
klog.Warningf("deployTo in metadata will NOT have any effect. It conflicts with %s policy named %s. Consider removing deployTo field in addon metadata.", v1alpha1.TopologyPolicyType, policy.Name)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func renderOutputs(addon *InstallPackage, args map[string]interface{}) ([]*unstructured.Unstructured, error) {
|
||||
outputs := map[string]interface{}{}
|
||||
r := addonCueTemplateRender{
|
||||
addon: addon,
|
||||
inputArgs: args,
|
||||
}
|
||||
if err := r.toObject(addon.AppCueTemplate.Data, renderAuxiliaryOutputsPath, &outputs); err != nil {
|
||||
if isErrorCueRenderPathNotFound(err, renderAuxiliaryOutputsPath) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
var res []*unstructured.Unstructured
|
||||
for _, o := range outputs {
|
||||
if ao, ok := o.(map[string]interface{}); ok {
|
||||
res = append(res, &unstructured.Unstructured{Object: ao})
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func isDeployToRuntime(addon *InstallPackage) bool {
|
||||
if addon.DeployTo == nil {
|
||||
return false
|
||||
|
||||
@@ -96,7 +96,12 @@ myref: {
|
||||
"namespace": "vela-system",
|
||||
},
|
||||
}
|
||||
app, err := render.renderApp()
|
||||
app, _, err := render.renderApp()
|
||||
assert.Equal(t, err.Error(), `load app template with CUE files: reference "myref" not found`)
|
||||
assert.Nil(t, app)
|
||||
|
||||
addon.CUETemplates = []ElementFile{{Data: "package main\n" + resourceComponent1}}
|
||||
app, _, err = render.renderApp()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(app.Spec.Components), 2)
|
||||
str, err := json.Marshal(app.Spec.Components[0].Properties)
|
||||
@@ -111,26 +116,29 @@ myref: {
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, strings.Contains(string(str), `"clusterLabelSelector":{}`))
|
||||
|
||||
addon.CUETemplates = []ElementFile{{Data: resourceComponent1}}
|
||||
addon.AppCueTemplate = ElementFile{Data: "package main\n" + appTemplate}
|
||||
app, err = render.renderApp()
|
||||
addon.Parameters = "package newp\n" + paraDefined
|
||||
addon.CUETemplates = []ElementFile{{Data: "package newp\n" + resourceComponent1}}
|
||||
addon.AppCueTemplate = ElementFile{Data: "package newp\n" + appTemplate}
|
||||
app, _, err = render.renderApp()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(app.Spec.Components), 2)
|
||||
|
||||
addon.Parameters = "package main\n" + paraDefined
|
||||
app, err = render.renderApp()
|
||||
addon.CUETemplates = []ElementFile{{Data: "package main\n" + resourceComponent1}}
|
||||
addon.Parameters = paraDefined
|
||||
addon.AppCueTemplate = ElementFile{Data: appTemplate}
|
||||
app, _, err = render.renderApp()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(app.Spec.Components), 2)
|
||||
|
||||
addon.CUETemplates = []ElementFile{{Data: "package hello\n" + resourceComponent1}}
|
||||
addon.AppCueTemplate = ElementFile{Data: "package main\n" + appTemplate}
|
||||
_, err = render.renderApp()
|
||||
_, _, err = render.renderApp()
|
||||
assert.Equal(t, err.Error(), `load app template with CUE files: reference "myref" not found`)
|
||||
|
||||
addon.CUETemplates = []ElementFile{{Data: "package hello\n" + resourceComponent1}}
|
||||
addon.Parameters = paraDefined
|
||||
addon.AppCueTemplate = ElementFile{Data: appTemplate}
|
||||
_, err = render.renderApp()
|
||||
_, _, err = render.renderApp()
|
||||
assert.Equal(t, err.Error(), `load app template with CUE files: reference "myref" not found`)
|
||||
|
||||
}
|
||||
@@ -234,21 +242,28 @@ func TestOutputsRender(t *testing.T) {
|
||||
Parameters: paraDefined,
|
||||
AppCueTemplate: ElementFile{Data: appTemplate},
|
||||
}
|
||||
list, err := renderOutputs(addon, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, len(list) == 1)
|
||||
|
||||
addon = &InstallPackage{
|
||||
Meta: Meta{
|
||||
Name: "velaux",
|
||||
DeployTo: &DeployTo{
|
||||
RuntimeCluster: true,
|
||||
},
|
||||
render := addonCueTemplateRender{
|
||||
addon: addon,
|
||||
inputArgs: map[string]interface{}{
|
||||
"namespace": "vela-system",
|
||||
},
|
||||
Parameters: paraDefined,
|
||||
AppCueTemplate: ElementFile{Data: appTemplateNoOutputs},
|
||||
}
|
||||
_, err = renderOutputs(addon, nil)
|
||||
app, auxdata, err := render.renderApp()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(app.Spec.Components), 1)
|
||||
str, err := json.Marshal(app.Spec.Components[0].Properties)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, strings.Contains(string(str), `{"name":"vela-system"}`))
|
||||
assert.Equal(t, len(auxdata), 1)
|
||||
auxStr, err := json.Marshal(auxdata[0])
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, strings.Contains(string(auxStr), "myData"))
|
||||
assert.True(t, strings.Contains(string(auxStr), "addons.oam.dev/auxiliary-name"))
|
||||
assert.True(t, strings.Contains(string(auxStr), "configmap"))
|
||||
|
||||
// test no error when no outputs
|
||||
addon.AppCueTemplate = ElementFile{Data: appTemplateNoOutputs}
|
||||
_, _, err = render.renderApp()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -369,7 +384,7 @@ func TestGenerateAppFrameworkWithCue(t *testing.T) {
|
||||
AppCueTemplate: ElementFile{Data: cueTemplate},
|
||||
Parameters: paraDefined,
|
||||
}
|
||||
app, err := generateAppFramework(cueAddon, map[string]interface{}{
|
||||
app, _, err := generateAppFramework(cueAddon, map[string]interface{}{
|
||||
"namespace": "vela-system",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
@@ -389,7 +404,7 @@ func TestGenerateAppFrameworkWithYamlTemplate(t *testing.T) {
|
||||
Meta: Meta{Name: "velaux"},
|
||||
AppTemplate: nil,
|
||||
}
|
||||
app, err := generateAppFramework(yamlAddon, nil)
|
||||
app, _, err := generateAppFramework(yamlAddon, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, app.Spec.Components != nil, true)
|
||||
assert.Equal(t, len(app.Labels), 2)
|
||||
@@ -398,7 +413,7 @@ func TestGenerateAppFrameworkWithYamlTemplate(t *testing.T) {
|
||||
Meta: Meta{Name: "velaux"},
|
||||
AppTemplate: &v1beta1.Application{},
|
||||
}
|
||||
app, err = generateAppFramework(noCompAddon, nil)
|
||||
app, _, err = generateAppFramework(noCompAddon, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, app.Spec.Components != nil, true)
|
||||
assert.Equal(t, len(app.Labels), 2)
|
||||
|
||||
@@ -27,6 +27,8 @@ import (
|
||||
errors "github.com/pkg/errors"
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chartutil"
|
||||
errors2 "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
rest "k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
@@ -36,6 +38,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/definition"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/addon"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
)
|
||||
|
||||
@@ -43,13 +46,22 @@ const (
|
||||
compDefAnnotation = "addon.oam.dev/componentDefinitions"
|
||||
traitDefAnnotation = "addon.oam.dev/traitDefinitions"
|
||||
workflowStepDefAnnotation = "addon.oam.dev/workflowStepDefinitions"
|
||||
policyDefAnnotation = "addon.oam.dev/policyDefinitions"
|
||||
defKeytemplate = "addon-%s-%s"
|
||||
compMapKey = "comp"
|
||||
traitMapKey = "trait"
|
||||
wfStepMapKey = "wfStep"
|
||||
policyMapKey = "policy"
|
||||
)
|
||||
|
||||
// parse addon's created x-defs in addon-app's annotation, this will be used to check whether app still using it while disabling.
|
||||
func passDefInAppAnnotation(defs []*unstructured.Unstructured, app *v1beta1.Application) error {
|
||||
var comps, traits, workflowSteps []string
|
||||
var comps, traits, workflowSteps, policies []string
|
||||
for _, def := range defs {
|
||||
if !checkBondComponentExist(*def, *app) {
|
||||
// if the definition binding a component, and the component not exist, skip recording.
|
||||
continue
|
||||
}
|
||||
switch def.GetObjectKind().GroupVersionKind().Kind {
|
||||
case v1beta1.ComponentDefinitionKind:
|
||||
comps = append(comps, def.GetName())
|
||||
@@ -57,6 +69,8 @@ func passDefInAppAnnotation(defs []*unstructured.Unstructured, app *v1beta1.Appl
|
||||
traits = append(traits, def.GetName())
|
||||
case v1beta1.WorkflowStepDefinitionKind:
|
||||
workflowSteps = append(workflowSteps, def.GetName())
|
||||
case v1beta1.PolicyDefinitionKind:
|
||||
policies = append(policies, def.GetName())
|
||||
default:
|
||||
return fmt.Errorf("cannot handle definition types %s, name %s", def.GetObjectKind().GroupVersionKind().Kind, def.GetName())
|
||||
}
|
||||
@@ -70,6 +84,9 @@ func passDefInAppAnnotation(defs []*unstructured.Unstructured, app *v1beta1.Appl
|
||||
if len(workflowSteps) != 0 {
|
||||
app.SetAnnotations(util.MergeMapOverrideWithDst(app.GetAnnotations(), map[string]string{workflowStepDefAnnotation: strings.Join(workflowSteps, ",")}))
|
||||
}
|
||||
if len(policies) != 0 {
|
||||
app.SetAnnotations(util.MergeMapOverrideWithDst(app.GetAnnotations(), map[string]string{policyDefAnnotation: strings.Join(policies, ",")}))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -87,7 +104,7 @@ func checkAddonHasBeenUsed(ctx context.Context, k8sClient client.Client, name st
|
||||
createdDefs := make(map[string]bool)
|
||||
for key, defNames := range addonApp.GetAnnotations() {
|
||||
switch key {
|
||||
case compDefAnnotation, traitDefAnnotation, workflowStepDefAnnotation:
|
||||
case compDefAnnotation, traitDefAnnotation, workflowStepDefAnnotation, policyDefAnnotation:
|
||||
merge2DefMap(key, defNames, createdDefs)
|
||||
}
|
||||
}
|
||||
@@ -102,25 +119,34 @@ func checkAddonHasBeenUsed(ctx context.Context, k8sClient client.Client, name st
|
||||
CHECKNEXT:
|
||||
for _, app := range apps.Items {
|
||||
for _, component := range app.Spec.Components {
|
||||
if createdDefs[fmt.Sprintf(defKeytemplate, "comp", component.Type)] {
|
||||
if createdDefs[fmt.Sprintf(defKeytemplate, compMapKey, component.Type)] {
|
||||
res = append(res, app)
|
||||
// this app has used this addon, there is no need check other components
|
||||
continue CHECKNEXT
|
||||
}
|
||||
for _, trait := range component.Traits {
|
||||
if createdDefs[fmt.Sprintf(defKeytemplate, "trait", trait.Type)] {
|
||||
if createdDefs[fmt.Sprintf(defKeytemplate, traitMapKey, trait.Type)] {
|
||||
res = append(res, app)
|
||||
continue CHECKNEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
if app.Spec.Workflow == nil || len(app.Spec.Workflow.Steps) == 0 {
|
||||
return res, nil
|
||||
|
||||
if app.Spec.Workflow != nil && len(app.Spec.Workflow.Steps) != 0 {
|
||||
for _, s := range app.Spec.Workflow.Steps {
|
||||
if createdDefs[fmt.Sprintf(defKeytemplate, wfStepMapKey, s.Type)] {
|
||||
res = append(res, app)
|
||||
continue CHECKNEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, s := range app.Spec.Workflow.Steps {
|
||||
if createdDefs[fmt.Sprintf(defKeytemplate, "wfStep", s.Type)] {
|
||||
res = append(res, app)
|
||||
continue CHECKNEXT
|
||||
|
||||
if app.Spec.Policies != nil && len(app.Spec.Policies) != 0 {
|
||||
for _, p := range app.Spec.Policies {
|
||||
if createdDefs[fmt.Sprintf(defKeytemplate, policyMapKey, p.Type)] {
|
||||
res = append(res, app)
|
||||
continue CHECKNEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,11 +160,13 @@ func merge2DefMap(defType string, defNames string, defMap map[string]bool) {
|
||||
for _, defName := range list {
|
||||
switch defType {
|
||||
case compDefAnnotation:
|
||||
defMap[fmt.Sprintf(template, "comp", defName)] = true
|
||||
defMap[fmt.Sprintf(template, compMapKey, defName)] = true
|
||||
case traitDefAnnotation:
|
||||
defMap[fmt.Sprintf(template, "trait", defName)] = true
|
||||
defMap[fmt.Sprintf(template, traitMapKey, defName)] = true
|
||||
case workflowStepDefAnnotation:
|
||||
defMap[fmt.Sprintf(template, "wfStep", defName)] = true
|
||||
defMap[fmt.Sprintf(template, wfStepMapKey, defName)] = true
|
||||
case policyDefAnnotation:
|
||||
defMap[fmt.Sprintf(template, policyMapKey, defName)] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,6 +238,8 @@ func findLegacyAddonDefs(ctx context.Context, k8sClient client.Client, addonName
|
||||
defs[fmt.Sprintf(defKeytemplate, "trait", defObject.GetName())] = true
|
||||
case v1beta1.WorkflowStepDefinitionKind:
|
||||
defs[fmt.Sprintf(defKeytemplate, "wfStep", defObject.GetName())] = true
|
||||
case v1beta1.PolicyDefinitionKind:
|
||||
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -242,6 +272,11 @@ func SkipValidateVersion(installer *Installer) {
|
||||
installer.skipVersionValidate = true
|
||||
}
|
||||
|
||||
// OverrideDefinitions menas override definitions within this addon if some of them already exist
|
||||
func OverrideDefinitions(installer *Installer) {
|
||||
installer.overrideDefs = true
|
||||
}
|
||||
|
||||
// IsAddonDir validates an addon directory.
|
||||
// It checks required files like metadata.yaml and template.yaml
|
||||
func IsAddonDir(dirName string) (bool, error) {
|
||||
@@ -409,3 +444,60 @@ func generateAnnotation(meta *Meta) map[string]string {
|
||||
func isErrorCueRenderPathNotFound(err error, path string) bool {
|
||||
return err.Error() == fmt.Sprintf("var(path=%s) not exist", path)
|
||||
}
|
||||
|
||||
func checkConflictDefs(ctx context.Context, k8sClient client.Client, defs []*unstructured.Unstructured, appName string) (map[string]string, error) {
|
||||
res := map[string]string{}
|
||||
for _, def := range defs {
|
||||
err := k8sClient.Get(ctx, client.ObjectKeyFromObject(def), def)
|
||||
if err == nil {
|
||||
owner := metav1.GetControllerOf(def)
|
||||
if owner == nil || owner.Kind != v1beta1.ApplicationKind {
|
||||
res[def.GetName()] = fmt.Sprintf("definition: %s already exist and not belong to any addon \n", def.GetName())
|
||||
continue
|
||||
}
|
||||
if owner.Name != appName {
|
||||
// if addon not belong to an addon or addon name is another one, we should put them in result
|
||||
res[def.GetName()] = fmt.Sprintf("definition: %s in this addon already exist in %s \n", def.GetName(), addon.AppName2Addon(appName))
|
||||
}
|
||||
}
|
||||
if err != nil && !errors2.IsNotFound(err) {
|
||||
return nil, errors.Wrapf(err, "check definition %s", def.GetName())
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func produceDefConflictError(conflictDefs map[string]string) error {
|
||||
if len(conflictDefs) == 0 {
|
||||
return nil
|
||||
}
|
||||
var errorInfo string
|
||||
for _, s := range conflictDefs {
|
||||
errorInfo += s
|
||||
}
|
||||
errorInfo += "if you want override them, please use argument '--override-definitions' to enable \n"
|
||||
return errors.New(errorInfo)
|
||||
}
|
||||
|
||||
// checkBondComponentExistt will check the ready-to-apply object(def or auxiliary outputs) whether bind to a component
|
||||
// if the target component not exist, return false.
|
||||
func checkBondComponentExist(u unstructured.Unstructured, app v1beta1.Application) bool {
|
||||
var comp string
|
||||
var existKey bool
|
||||
comp, existKey = u.GetAnnotations()[oam.AnnotationAddonDefinitionBondCompKey]
|
||||
if !existKey {
|
||||
// this is compatibility logic for deprecated annotation
|
||||
comp, existKey = u.GetAnnotations()[oam.AnnotationIgnoreWithoutCompKey]
|
||||
if !existKey {
|
||||
// if an object(def or auxiliary outputs ) binding no components return true
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, component := range app.Spec.Components {
|
||||
if component.Name == comp {
|
||||
// the bond component exists, return ture
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
velatypes "github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
@@ -108,9 +109,13 @@ var _ = Describe("Test definition check", func() {
|
||||
Expect(yaml.Unmarshal([]byte(testApp3Yaml), &app3)).Should(BeNil())
|
||||
Expect(k8sClient.Create(ctx, &app3)).Should(BeNil())
|
||||
|
||||
app4 := v1beta1.Application{}
|
||||
Expect(yaml.Unmarshal([]byte(testApp4Yaml), &app4)).Should(BeNil())
|
||||
Expect(k8sClient.Create(ctx, &app4)).Should(BeNil())
|
||||
|
||||
usedApps, err := checkAddonHasBeenUsed(ctx, k8sClient, "my-addon", addonApp, cfg)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(usedApps)).Should(BeEquivalentTo(3))
|
||||
Expect(len(usedApps)).Should(BeEquivalentTo(4))
|
||||
})
|
||||
|
||||
It("check fetch lagacy addon definitions", func() {
|
||||
@@ -283,6 +288,47 @@ func TestMakeChart(t *testing.T) {
|
||||
assert.Equal(t, isChartDir, true)
|
||||
}
|
||||
|
||||
func TestCheckObjectBindingComponent(t *testing.T) {
|
||||
existingBindingDef := unstructured.Unstructured{}
|
||||
existingBindingDef.SetAnnotations(map[string]string{oam.AnnotationAddonDefinitionBondCompKey: "kustomize"})
|
||||
|
||||
emptyAnnoDef := unstructured.Unstructured{}
|
||||
emptyAnnoDef.SetAnnotations(map[string]string{"test": "onlyForTest"})
|
||||
|
||||
legacyAnnoDef := unstructured.Unstructured{}
|
||||
legacyAnnoDef.SetAnnotations(map[string]string{oam.AnnotationIgnoreWithoutCompKey: "kustomize"})
|
||||
testCases := map[string]struct {
|
||||
object unstructured.Unstructured
|
||||
app v1beta1.Application
|
||||
res bool
|
||||
}{
|
||||
"bindingExist": {object: existingBindingDef,
|
||||
app: v1beta1.Application{Spec: v1beta1.ApplicationSpec{Components: []common.ApplicationComponent{{Name: "kustomize"}}}},
|
||||
res: true},
|
||||
"NotExisting": {object: existingBindingDef,
|
||||
app: v1beta1.Application{Spec: v1beta1.ApplicationSpec{Components: []common.ApplicationComponent{{Name: "helm"}}}},
|
||||
res: false},
|
||||
"NoBidingAnnotation": {object: emptyAnnoDef,
|
||||
app: v1beta1.Application{Spec: v1beta1.ApplicationSpec{Components: []common.ApplicationComponent{{Name: "kustomize"}}}},
|
||||
res: true},
|
||||
"EmptyApp": {object: existingBindingDef,
|
||||
app: v1beta1.Application{Spec: v1beta1.ApplicationSpec{Components: []common.ApplicationComponent{}}},
|
||||
res: false},
|
||||
"LegacyApp": {object: legacyAnnoDef,
|
||||
app: v1beta1.Application{Spec: v1beta1.ApplicationSpec{Components: []common.ApplicationComponent{{Name: "kustomize"}}}},
|
||||
res: true,
|
||||
},
|
||||
"LegacyAppWithoutComp": {object: legacyAnnoDef,
|
||||
app: v1beta1.Application{Spec: v1beta1.ApplicationSpec{Components: []common.ApplicationComponent{{}}}},
|
||||
res: false,
|
||||
},
|
||||
}
|
||||
for _, s := range testCases {
|
||||
result := checkBondComponentExist(s.object, s.app)
|
||||
assert.Equal(t, result, s.res)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
compDefYaml = `
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
@@ -319,6 +365,7 @@ metadata:
|
||||
addon.oam.dev/componentDefinitions: "my-comp"
|
||||
addon.oam.dev/traitDefinitions: "my-trait"
|
||||
addon.oam.dev/workflowStepDefinitions: "my-wfstep"
|
||||
addon.oam.dev/policyDefinitions: "my-policy"
|
||||
name: addon-myaddon
|
||||
namespace: vela-system
|
||||
spec:
|
||||
@@ -367,6 +414,22 @@ spec:
|
||||
- type: my-wfstep
|
||||
name: deploy
|
||||
`
|
||||
testApp4Yaml = `
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app-4
|
||||
namespace: test-ns
|
||||
spec:
|
||||
components:
|
||||
- name: podinfo
|
||||
type: webservice
|
||||
|
||||
policies:
|
||||
- type: my-policy
|
||||
name: topology
|
||||
`
|
||||
|
||||
registryCmYaml = `
|
||||
apiVersion: v1
|
||||
data:
|
||||
|
||||
@@ -86,6 +86,7 @@ func (i *versionedRegistry) GetAddonUIData(ctx context.Context, addonName, versi
|
||||
Detail: wholePackage.Detail,
|
||||
Definitions: wholePackage.Definitions,
|
||||
AvailableVersions: wholePackage.AvailableVersions,
|
||||
CUEDefinitions: wholePackage.CUEDefinitions,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -32,11 +32,12 @@ const (
|
||||
// SystemInfo systemInfo model
|
||||
type SystemInfo struct {
|
||||
BaseModel
|
||||
InstallID string `json:"installID"`
|
||||
EnableCollection bool `json:"enableCollection"`
|
||||
StatisticInfo StatisticInfo `json:"statisticInfo,omitempty"`
|
||||
LoginType string `json:"loginType"`
|
||||
DexUserDefaultProjects []ProjectRef `json:"projects"`
|
||||
InstallID string `json:"installID"`
|
||||
EnableCollection bool `json:"enableCollection"`
|
||||
StatisticInfo StatisticInfo `json:"statisticInfo,omitempty"`
|
||||
LoginType string `json:"loginType"`
|
||||
DexUserDefaultProjects []ProjectRef `json:"projects"`
|
||||
DexUserDefaultPlatformRoles []string `json:"dexUserDefaultPlatformRoles"`
|
||||
}
|
||||
|
||||
// ProjectRef set the project name and roles
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
errors3 "github.com/pkg/errors"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
errors2 "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
@@ -44,6 +45,7 @@ import (
|
||||
"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/definition"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
addonutil "github.com/oam-dev/kubevela/pkg/utils/addon"
|
||||
@@ -68,7 +70,7 @@ type AddonService interface {
|
||||
}
|
||||
|
||||
// AddonImpl2AddonRes convert pkgaddon.UIData to the type apiserver need
|
||||
func AddonImpl2AddonRes(impl *pkgaddon.UIData) (*apis.DetailAddonResponse, error) {
|
||||
func AddonImpl2AddonRes(impl *pkgaddon.UIData, config *rest.Config) (*apis.DetailAddonResponse, error) {
|
||||
var defs []*apis.AddonDefinition
|
||||
for _, def := range impl.Definitions {
|
||||
obj := &unstructured.Unstructured{}
|
||||
@@ -83,6 +85,20 @@ func AddonImpl2AddonRes(impl *pkgaddon.UIData) (*apis.DetailAddonResponse, error
|
||||
Description: obj.GetAnnotations()["definition.oam.dev/description"],
|
||||
})
|
||||
}
|
||||
|
||||
for _, cueDef := range impl.CUEDefinitions {
|
||||
def := definition.Definition{Unstructured: unstructured.Unstructured{}}
|
||||
err := def.FromCUEString(cueDef.Data, config)
|
||||
if err != nil {
|
||||
return nil, errors3.Wrapf(err, "fail to render definition: %s in cue's format", cueDef.Name)
|
||||
}
|
||||
defs = append(defs, &apis.AddonDefinition{
|
||||
Name: def.GetName(),
|
||||
DefType: def.GetKind(),
|
||||
Description: def.GetAnnotations()["definition.oam.dev/description"],
|
||||
})
|
||||
}
|
||||
|
||||
if impl.Meta.DeployTo != nil && impl.Meta.DeployTo.LegacyRuntimeCluster != impl.Meta.DeployTo.RuntimeCluster {
|
||||
impl.Meta.DeployTo.LegacyRuntimeCluster = impl.Meta.DeployTo.LegacyRuntimeCluster || impl.Meta.DeployTo.RuntimeCluster
|
||||
impl.Meta.DeployTo.RuntimeCluster = impl.Meta.DeployTo.LegacyRuntimeCluster || impl.Meta.DeployTo.RuntimeCluster
|
||||
@@ -175,7 +191,7 @@ func (u *addonServiceImpl) GetAddon(ctx context.Context, name string, registry s
|
||||
|
||||
addon.UISchema = renderAddonCustomUISchema(ctx, u.kubeClient, name, renderDefaultUISchema(addon.APISchema))
|
||||
|
||||
a, err := AddonImpl2AddonRes(addon)
|
||||
a, err := AddonImpl2AddonRes(addon, u.config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -284,7 +300,7 @@ func (u *addonServiceImpl) ListAddons(ctx context.Context, registry, query strin
|
||||
|
||||
var addonResources []*apis.DetailAddonResponse
|
||||
for _, a := range addons {
|
||||
addonRes, err := AddonImpl2AddonRes(a)
|
||||
addonRes, err := AddonImpl2AddonRes(a, u.config)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("err while converting AddonImpl to DetailAddonResponse: %v", err)
|
||||
continue
|
||||
|
||||
@@ -484,6 +484,10 @@ func (d *dexHandlerImpl) login(ctx context.Context) (*apisv1.UserBase, error) {
|
||||
}
|
||||
userBase = convertUserBase(u)
|
||||
} else {
|
||||
systemInfo, err := d.systemInfoService.GetSystemInfo(ctx)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("failed to get the system info %s", err.Error())
|
||||
}
|
||||
user := &model.User{
|
||||
Email: claims.Email,
|
||||
Name: strings.ToLower(claims.Sub),
|
||||
@@ -491,18 +495,17 @@ func (d *dexHandlerImpl) login(ctx context.Context) (*apisv1.UserBase, error) {
|
||||
Alias: claims.Name,
|
||||
LastLoginTime: time.Now(),
|
||||
}
|
||||
if systemInfo != nil {
|
||||
user.UserRoles = systemInfo.DexUserDefaultPlatformRoles
|
||||
}
|
||||
if err := d.Store.Add(ctx, user); err != nil {
|
||||
log.Logger.Errorf("failed to save the user from the dex: %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
systemInfo, err := d.systemInfoService.GetSystemInfo(ctx)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("failed to get the system info %s", err.Error())
|
||||
}
|
||||
if systemInfo != nil {
|
||||
for _, project := range systemInfo.DexUserDefaultProjects {
|
||||
_, err := d.projectService.AddProjectUser(ctx, project.Name, apisv1.AddProjectUserRequest{
|
||||
UserName: claims.Sub,
|
||||
UserName: strings.ToLower(claims.Sub),
|
||||
UserRoles: project.Roles,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
. "github.com/agiledragon/gomonkey/v2"
|
||||
@@ -65,7 +66,7 @@ var _ = Describe("Test authentication service functions", func() {
|
||||
})
|
||||
It("Test Dex login", func() {
|
||||
testIDToken := &oidc.IDToken{}
|
||||
sub := "248289761001"
|
||||
sub := "248289761001Abv"
|
||||
patch := ApplyMethod(reflect.TypeOf(testIDToken), "Claims", func(_ *oidc.IDToken, v interface{}) error {
|
||||
return json.Unmarshal([]byte(fmt.Sprintf(`{"email":"test@test.com", "name":"show name", "sub": "%s"}`, sub)), v)
|
||||
})
|
||||
@@ -78,13 +79,14 @@ var _ = Describe("Test authentication service functions", func() {
|
||||
err = projectService.Init(context.TODO())
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
_, err = sysService.UpdateSystemInfo(context.TODO(), apisv1.SystemInfoRequest{
|
||||
LoginType: "local",
|
||||
DexUserDefaultProjects: []model.ProjectRef{{
|
||||
Name: "default",
|
||||
Roles: []string{"app-developer"},
|
||||
}},
|
||||
})
|
||||
info, err := sysService.Get(context.TODO())
|
||||
Expect(err).Should(BeNil())
|
||||
info.DexUserDefaultProjects = []model.ProjectRef{{
|
||||
Name: "default",
|
||||
Roles: []string{"app-developer"},
|
||||
}}
|
||||
info.DexUserDefaultPlatformRoles = []string{"admin"}
|
||||
err = ds.Put(context.TODO(), info)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
dexHandler := dexHandlerImpl{
|
||||
@@ -96,9 +98,14 @@ var _ = Describe("Test authentication service functions", func() {
|
||||
resp, err := dexHandler.login(context.Background())
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(resp.Email).Should(Equal("test@test.com"))
|
||||
Expect(resp.Name).Should(Equal(sub))
|
||||
Expect(resp.Name).Should(Equal(strings.ToLower(sub)))
|
||||
Expect(resp.Alias).Should(Equal("show name"))
|
||||
|
||||
newUser, err := userService.GetUser(context.TODO(), resp.Name)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(newUser.DexSub).Should(Equal(sub))
|
||||
Expect(newUser.UserRoles).Should(Equal([]string{"admin"}))
|
||||
|
||||
projects, err := projectService.ListUserProjects(context.TODO(), sub)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(projects)).Should(Equal(1))
|
||||
|
||||
@@ -75,6 +75,7 @@ const (
|
||||
type CloudShellService interface {
|
||||
Prepare(ctx context.Context) (*apisv1.CloudShellPrepareResponse, error)
|
||||
GetCloudShellEndpoint(ctx context.Context) (string, error)
|
||||
Destroy(ctx context.Context) error
|
||||
}
|
||||
|
||||
// GenerateKubeConfig generate the kubeconfig for the cloudshell
|
||||
@@ -157,6 +158,32 @@ func (c *cloudShellServiceImpl) Prepare(ctx context.Context) (*apisv1.CloudShell
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Destroy destroy the cloud shell environment
|
||||
func (c *cloudShellServiceImpl) Destroy(ctx context.Context) error {
|
||||
var userName string
|
||||
if user := ctx.Value(&apisv1.CtxKeyUser); user != nil {
|
||||
if u, ok := user.(string); ok {
|
||||
userName = u
|
||||
}
|
||||
}
|
||||
if userName == "" {
|
||||
return bcode.ErrUnauthorized
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second*20)
|
||||
defer cancel()
|
||||
var cloudShell v1alpha1.CloudShell
|
||||
if err := c.KubeClient.Get(ctx, types.NamespacedName{Namespace: kubevelatypes.DefaultKubeVelaNS, Name: makeUserCloudShellName(userName)}, &cloudShell); err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
if meta.IsNoMatchError(err) {
|
||||
return bcode.ErrCloudShellAddonNotEnabled
|
||||
}
|
||||
return err
|
||||
}
|
||||
return c.KubeClient.Delete(ctx, &cloudShell)
|
||||
}
|
||||
|
||||
func (c *cloudShellServiceImpl) GetCloudShellEndpoint(ctx context.Context) (string, error) {
|
||||
var userName string
|
||||
if user := ctx.Value(&apisv1.CtxKeyUser); user != nil {
|
||||
@@ -182,7 +209,7 @@ func (c *cloudShellServiceImpl) GetCloudShellEndpoint(ctx context.Context) (stri
|
||||
return cloudShell.Status.AccessURL, nil
|
||||
}
|
||||
|
||||
// prepareKubeConfig prepare the user's kubeconfig
|
||||
// prepareKubeConfig prepare the user's kube config
|
||||
func (c *cloudShellServiceImpl) prepareKubeConfig(ctx context.Context) error {
|
||||
var userName string
|
||||
if user := ctx.Value(&apisv1.CtxKeyUser); user != nil {
|
||||
@@ -212,10 +239,13 @@ func (c *cloudShellServiceImpl) prepareKubeConfig(ctx context.Context) error {
|
||||
readOnly = checkReadOnly(p.Name, permissions)
|
||||
}
|
||||
if readOnly {
|
||||
// TODO:(@barnettZQG) there needs a method to revoke the privileges
|
||||
if err := c.managePrivilegesForUser(ctx, p.Name, true, userName, false); err != nil {
|
||||
groupName, err := c.managePrivilegesForProjectRead(ctx, p.Name, true)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("failed to privileges the user %s", err.Error())
|
||||
}
|
||||
if groupName != "" {
|
||||
groups = append(groups, groupName)
|
||||
}
|
||||
} else {
|
||||
groups = append(groups, utils.KubeVelaProjectGroupPrefix+p.Name)
|
||||
}
|
||||
@@ -345,8 +375,8 @@ func checkReadOnly(projectName string, permissions []*model.Permission) bool {
|
||||
return !ra.Match(permissions)
|
||||
}
|
||||
|
||||
// managePrivilegesForUser grant or revoke privileges for a user
|
||||
func (c *cloudShellServiceImpl) managePrivilegesForUser(ctx context.Context, projectName string, readOnly bool, userName string, revoke bool) error {
|
||||
// managePrivilegesForProjectRead grant the read privileges for a project
|
||||
func (c *cloudShellServiceImpl) managePrivilegesForProjectRead(ctx context.Context, projectName string, readOnly bool) (string, error) {
|
||||
targets, err := c.TargetService.ListTargets(ctx, 0, 0, projectName)
|
||||
if err != nil {
|
||||
log.Logger.Infof("failed to list the targets by the project name %s :%s", projectName, err.Error())
|
||||
@@ -362,16 +392,12 @@ func (c *cloudShellServiceImpl) managePrivilegesForUser(ctx context.Context, pro
|
||||
for _, e := range envs.Envs {
|
||||
authPDs = append(authPDs, &auth.ApplicationPrivilege{Cluster: kubevelatypes.ClusterLocalName, Namespace: e.Namespace, ReadOnly: readOnly})
|
||||
}
|
||||
|
||||
identity := &auth.Identity{User: userName}
|
||||
groupName := utils.KubeVelaProjectReadGroupPrefix + projectName
|
||||
identity := &auth.Identity{Groups: []string{groupName}}
|
||||
writer := &bytes.Buffer{}
|
||||
f, msg := auth.GrantPrivileges, "GrantPrivileges"
|
||||
if revoke {
|
||||
f, msg = auth.RevokePrivileges, "RevokePrivileges"
|
||||
if err := auth.GrantPrivileges(ctx, c.KubeClient, authPDs, identity, writer, auth.WithReplace); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := f(ctx, c.KubeClient, authPDs, identity, writer); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Logger.Debugf("%s: %s", msg, writer.String())
|
||||
return nil
|
||||
log.Logger.Debugf("GrantPrivileges: %s", writer.String())
|
||||
return groupName, nil
|
||||
}
|
||||
|
||||
@@ -154,10 +154,13 @@ var _ = Describe("Test cloudshell service function", func() {
|
||||
err = k8sClient.Get(context.Background(), types.NamespacedName{Name: "kubevela:reader:application:binding", Namespace: "default"}, &rb)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(rb.Subjects)).Should(Equal(1))
|
||||
Expect(rb.Subjects[0].Name).Should(Equal("test-viewer"))
|
||||
Expect(rb.Subjects[0].Kind).Should(Equal("User"))
|
||||
Expect(rb.Subjects[0].Name).Should(Equal(utils.KubeVelaProjectReadGroupPrefix + "default"))
|
||||
Expect(rb.Subjects[0].Kind).Should(Equal("Group"))
|
||||
err = k8sClient.Get(context.Background(), types.NamespacedName{Name: "kubevela:reader:binding", Namespace: "default"}, &rb)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(rb.Subjects)).Should(Equal(1))
|
||||
Expect(rb.Subjects[0].Name).Should(Equal(utils.KubeVelaProjectReadGroupPrefix + "default"))
|
||||
Expect(rb.Subjects[0].Kind).Should(Equal("Group"))
|
||||
|
||||
By("test the administrator users")
|
||||
|
||||
@@ -178,7 +181,7 @@ var _ = Describe("Test cloudshell service function", func() {
|
||||
})
|
||||
|
||||
It("test prepare", func() {
|
||||
By("With not CRD")
|
||||
By("Test with not CRD")
|
||||
_, err = userService.CreateUser(context.TODO(), apisv1.CreateUserRequest{Name: "test", Password: "test"})
|
||||
Expect(err).Should(BeNil())
|
||||
ctx := context.WithValue(context.TODO(), &apisv1.CtxKeyUser, "test")
|
||||
@@ -186,6 +189,7 @@ var _ = Describe("Test cloudshell service function", func() {
|
||||
Expect(err).ShouldNot(BeNil())
|
||||
Expect(err.Error()).Should(Equal(bcode.ErrCloudShellAddonNotEnabled.Error()))
|
||||
|
||||
By("Test with CRD")
|
||||
cloudshellCRDBytes, err := ioutil.ReadFile("./testdata/cloudshell-crd.yaml")
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
@@ -210,8 +214,12 @@ var _ = Describe("Test cloudshell service function", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(re.Status).Should(Equal(StatusCompleted))
|
||||
|
||||
By("Test get the cloud shell endpoint")
|
||||
endpoint, err := cloudShellService.GetCloudShellEndpoint(ctx)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(endpoint).Should(Equal("10.10.1.1:8765"))
|
||||
|
||||
By("Test destroy cloud shell")
|
||||
Expect(cloudShellService.Destroy(ctx)).Should(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
@@ -72,7 +72,7 @@ func (u *configServiceImpl) ListConfigTypes(ctx context.Context, query string) (
|
||||
defs := &v1beta1.ComponentDefinitionList{}
|
||||
if err := u.KubeClient.List(ctx, defs, client.InNamespace(types.DefaultKubeVelaNS),
|
||||
client.MatchingLabels{
|
||||
configCatalog: types.VelaCoreConfig,
|
||||
definition.ConfigCatalog: types.VelaCoreConfig,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -85,12 +85,17 @@ func (u *configServiceImpl) ListConfigTypes(ctx context.Context, query string) (
|
||||
if err := u.KubeClient.List(ctx, defsLegacy, client.InNamespace(types.DefaultKubeVelaNS),
|
||||
client.MatchingLabels{
|
||||
// leave here as the legacy format to test the compatibility
|
||||
definition.UserPrefix + configCatalog: types.VelaCoreConfig,
|
||||
definition.UserPrefix + definition.ConfigCatalog: types.VelaCoreConfig,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, defsLegacy.Items...)
|
||||
|
||||
// filter repeated config,due to new labels that exist at the same time
|
||||
for _, legacy := range defsLegacy.Items {
|
||||
if legacy.Labels[definition.ConfigCatalog] == types.VelaCoreConfig {
|
||||
continue
|
||||
}
|
||||
items = append(items, legacy)
|
||||
}
|
||||
var tfDefs []v1beta1.ComponentDefinition
|
||||
var configTypes []*apis.ConfigType
|
||||
|
||||
|
||||
@@ -57,8 +57,8 @@ func TestListConfigTypes(t *testing.T) {
|
||||
Name: "def1",
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Labels: map[string]string{
|
||||
configCatalog: types.VelaCoreConfig,
|
||||
definitionType: types.TerraformProvider,
|
||||
definition.ConfigCatalog: types.VelaCoreConfig,
|
||||
definition.DefinitionType: types.TerraformProvider,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -71,10 +71,10 @@ func TestListConfigTypes(t *testing.T) {
|
||||
Name: "def2",
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Annotations: map[string]string{
|
||||
definitionAlias: "Def2",
|
||||
definition.DefinitionAlias: "Def2",
|
||||
},
|
||||
Labels: map[string]string{
|
||||
configCatalog: types.VelaCoreConfig,
|
||||
definition.ConfigCatalog: types.VelaCoreConfig,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -153,10 +153,10 @@ func TestGetConfigType(t *testing.T) {
|
||||
Name: "def2",
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Annotations: map[string]string{
|
||||
definitionAlias: "Def2",
|
||||
definition.DefinitionAlias: "Def2",
|
||||
},
|
||||
Labels: map[string]string{
|
||||
definition.UserPrefix + configCatalog: types.VelaCoreConfig,
|
||||
definition.UserPrefix + definition.ConfigCatalog: types.VelaCoreConfig,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -484,7 +484,7 @@ func (p *rbacServiceImpl) GetUserPermissions(ctx context.Context, user *model.Us
|
||||
perms = append(perms, &model.Permission{
|
||||
Name: "cloudshell",
|
||||
Resources: []string{"cloudshell"},
|
||||
Actions: []string{"create"},
|
||||
Actions: []string{"*"},
|
||||
Effect: "Allow",
|
||||
})
|
||||
return perms, nil
|
||||
|
||||
@@ -113,8 +113,9 @@ func (u systemInfoServiceImpl) UpdateSystemInfo(ctx context.Context, sysInfo v1.
|
||||
CreateTime: info.CreateTime,
|
||||
UpdateTime: time.Now(),
|
||||
},
|
||||
StatisticInfo: info.StatisticInfo,
|
||||
DexUserDefaultProjects: sysInfo.DexUserDefaultProjects,
|
||||
StatisticInfo: info.StatisticInfo,
|
||||
DexUserDefaultProjects: sysInfo.DexUserDefaultProjects,
|
||||
DexUserDefaultPlatformRoles: info.DexUserDefaultPlatformRoles,
|
||||
}
|
||||
|
||||
if sysInfo.LoginType == model.LoginTypeDex {
|
||||
@@ -167,10 +168,11 @@ func (u systemInfoServiceImpl) Init(ctx context.Context) error {
|
||||
|
||||
func convertInfoToBase(info *model.SystemInfo) v1.SystemInfo {
|
||||
return v1.SystemInfo{
|
||||
PlatformID: info.InstallID,
|
||||
EnableCollection: info.EnableCollection,
|
||||
LoginType: info.LoginType,
|
||||
InstallTime: info.CreateTime,
|
||||
DexUserDefaultProjects: info.DexUserDefaultProjects,
|
||||
PlatformID: info.InstallID,
|
||||
EnableCollection: info.EnableCollection,
|
||||
LoginType: info.LoginType,
|
||||
InstallTime: info.CreateTime,
|
||||
DexUserDefaultProjects: info.DexUserDefaultProjects,
|
||||
DexUserDefaultPlatformRoles: info.DexUserDefaultPlatformRoles,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,22 +18,16 @@ package service
|
||||
|
||||
import "github.com/oam-dev/kubevela/pkg/definition"
|
||||
|
||||
const (
|
||||
definitionAlias = "alias.config.oam.dev"
|
||||
definitionType = "type.config.oam.dev"
|
||||
configCatalog = "catalog.config.oam.dev"
|
||||
)
|
||||
|
||||
// DefinitionAlias will get definitionAlias value from tags
|
||||
func DefinitionAlias(tags map[string]string) string {
|
||||
if tags == nil {
|
||||
return ""
|
||||
}
|
||||
val := tags[definitionAlias]
|
||||
val := tags[definition.DefinitionAlias]
|
||||
if val != "" {
|
||||
return val
|
||||
}
|
||||
return tags[definition.UserPrefix+definitionAlias]
|
||||
return tags[definition.UserPrefix+definition.DefinitionAlias]
|
||||
}
|
||||
|
||||
// DefinitionType will get definitionType value from tags
|
||||
@@ -41,11 +35,11 @@ func DefinitionType(tags map[string]string) string {
|
||||
if tags == nil {
|
||||
return ""
|
||||
}
|
||||
val := tags[definitionType]
|
||||
val := tags[definition.DefinitionType]
|
||||
if val != "" {
|
||||
return val
|
||||
}
|
||||
return tags[definition.UserPrefix+definitionType]
|
||||
return tags[definition.UserPrefix+definition.DefinitionType]
|
||||
}
|
||||
|
||||
// ConfigCatalog will get configCatalog value from tags
|
||||
@@ -53,9 +47,9 @@ func ConfigCatalog(tags map[string]string) string {
|
||||
if tags == nil {
|
||||
return ""
|
||||
}
|
||||
val := tags[configCatalog]
|
||||
val := tags[definition.ConfigCatalog]
|
||||
if val != "" {
|
||||
return val
|
||||
}
|
||||
return tags[definition.UserPrefix+configCatalog]
|
||||
return tags[definition.UserPrefix+definition.ConfigCatalog]
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user