Feat: vela can set default namespace and user can enable fluxcd addon by default (#3280)

* vela default namespace and enable addon by default

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

* fix lint

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

fix cli error

fix comments

* add tests

Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
This commit is contained in:
wyike
2022-02-18 17:23:50 +08:00
committed by GitHub
parent 67e88ffbaf
commit 015f3cf72b
11 changed files with 5461 additions and 44 deletions
+3 -2
View File
@@ -19,8 +19,6 @@ package types
import "github.com/oam-dev/kubevela/pkg/oam"
const (
// DefaultKubeVelaNS defines the default KubeVela namespace in Kubernetes
DefaultKubeVelaNS = "vela-system"
// DefaultKubeVelaReleaseName defines the default name of KubeVela Release
DefaultKubeVelaReleaseName = "kubevela"
// DefaultKubeVelaChartName defines the default chart name of KubeVela, this variable MUST align to the chart name of this repo
@@ -35,6 +33,9 @@ const (
AutoDetectWorkloadDefinition = "autodetects.core.oam.dev"
)
// DefaultKubeVelaNS defines the default KubeVela namespace in Kubernetes
var DefaultKubeVelaNS = "vela-system"
const (
// AnnoDefinitionDescription is the annotation which describe what is the capability used for in a WorkloadDefinition/TraitDefinition Object
AnnoDefinitionDescription = "definition.oam.dev/description"
@@ -0,0 +1,268 @@
{{- if .Values.enableFluxcdAddon -}}
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
labels:
addons.oam.dev/name: fluxcd-def
name: addon-fluxcd-def
namespace: {{ .Release.Namespace }}
spec:
components:
- name: fluxc-def-resources
properties:
objects:
- apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: helm release is a group of K8s resources
from either git repository or helm repo
name: helm
namespace: {{.Values.systemDefinitionNamespace}}
spec:
schematic:
cue:
template: "output: {\n\tapiVersion: \"source.toolkit.fluxcd.io/v1beta1\"\n\tmetadata:
{\n\t\tname: context.name\n\t}\n\tif parameter.repoType == \"git\"
{\n\t\tkind: \"GitRepository\"\n\t\tspec: {\n\t\t\turl: parameter.url\n\t\t\tif
parameter.git.branch != _|_ {\n\t\t\t\tref: branch: parameter.git.branch\n\t\t\t}\n\t\t\t_secret\n\t\t\t_sourceCommonArgs\n\t\t}\n\t}\n\tif
parameter.repoType == \"oss\" {\n\t\tkind: \"Bucket\"\n\t\tspec: {\n\t\t\tendpoint:
\ parameter.url\n\t\t\tbucketName: parameter.oss.bucketName\n\t\t\tprovider:
\ parameter.oss.provider\n\t\t\tif parameter.oss.region != _|_ {\n\t\t\t\tregion:
parameter.oss.region\n\t\t\t}\n\t\t\t_secret\n\t\t\t_sourceCommonArgs\n\t\t}\n\t}\n\tif
parameter.repoType == \"helm\" {\n\t\tkind: \"HelmRepository\"\n\t\tspec:
{\n\t\t\turl: parameter.url\n\t\t\t_secret\n\t\t\t_sourceCommonArgs\n\t\t}\n\t}\n}\n\noutputs:
release: {\n\tapiVersion: \"helm.toolkit.fluxcd.io/v2beta1\"\n\tkind:
\ \"HelmRelease\"\n\tmetadata: {\n\t\tname: context.name\n\t}\n\tspec:
{\n\t\ttimeout: parameter.installTimeout\n\t\tinterval: parameter.interval\n\t\tchart:
{\n\t\t\tspec: {\n\t\t\t\tchart: parameter.chart\n\t\t\t\tversion:
parameter.version\n\t\t\t\tsourceRef: {\n\t\t\t\t\tif parameter.repoType
== \"git\" {\n\t\t\t\t\t\tkind: \"GitRepository\"\n\t\t\t\t\t}\n\t\t\t\t\tif
parameter.repoType == \"helm\" {\n\t\t\t\t\t\tkind: \"HelmRepository\"\n\t\t\t\t\t}\n\t\t\t\t\tif
parameter.repoType == \"oss\" {\n\t\t\t\t\t\tkind: \"Bucket\"\n\t\t\t\t\t}\n\t\t\t\t\tname:
\ context.name\n\t\t\t\t}\n\t\t\t\tinterval: parameter.interval\n\t\t\t}\n\t\t}\n\t\tif
parameter.targetNamespace != _|_ {\n\t\t\ttargetNamespace: parameter.targetNamespace\n\t\t}\n\t\tif
parameter.releaseName != _|_ {\n\t\t\treleaseName: parameter.releaseName\n\t\t}\n\t\tif
parameter.values != _|_ {\n\t\t\tvalues: parameter.values\n\t\t}\n\t}\n}\n\n_secret:
{\n\tif parameter.secretRef != _|_ {\n\t\tsecretRef: {\n\t\t\tname:
parameter.secretRef\n\t\t}\n\t}\n}\n\n_sourceCommonArgs: {\n\tinterval:
parameter.pullInterval\n\tif parameter.timeout != _|_ {\n\t\ttimeout:
parameter.timeout\n\t}\n}\n\nparameter: {\n\trepoType: *\"helm\" |
\"git\" | \"oss\"\n\t// +usage=The interval at which to check for
repository/bucket and relese updates, default to 5m\n\tpullInterval:
*\"5m\" | string\n // +usage=The Interval at which to reconcile
the Helm release, default to 30s\n interval: *\"30s\" | string\n\t//
+usage=The Git or Helm repository URL, OSS endpoint, accept HTTP/S
or SSH address as git url,\n\turl: string\n\t// +usage=The name of
the secret containing authentication credentials\n\tsecretRef?: string\n\t//
+usage=The timeout for operations like download index/clone repository,
optional\n\ttimeout?: string\n\t// +usage=The timeout for operation
`helm install`, optional\n\tinstallTimeout: *\"10m\" | string\n\n\tgit?:
{\n\t\t// +usage=The Git reference to checkout and monitor for changes,
defaults to master branch\n\t\tbranch: string\n\t}\n\toss?: {\n\t\t//
+usage=The bucket's name, required if repoType is oss\n\t\tbucketName:
string\n\t\t// +usage=\"generic\" for Minio, Amazon S3, Google Cloud
Storage, Alibaba Cloud OSS, \"aws\" for retrieve credentials from
the EC2 service when credentials not specified, default \"generic\"\n\t\tprovider:
*\"generic\" | \"aws\"\n\t\t// +usage=The bucket region, optional\n\t\tregion?:
string\n\t}\n\n\t// +usage=1.The relative path to helm chart for git/oss
source. 2. chart name for helm resource 3. relative path for chart
package(e.g. ./charts/podinfo-1.2.3.tgz)\n\tchart: string\n\t// +usage=Chart
version\n\tversion: *\"*\" | string\n\t// +usage=The namespace for
helm chart, optional\n\ttargetNamespace?: string\n\t// +usage=The
release name\n\treleaseName?: string\n\t// +usage=Chart values\n\tvalues?:
#nestedmap\n}\n\n#nestedmap: {\n\t...\n}\n"
status:
customStatus: "repoMessage: string\nreleaseMessage: string\nif context.output.status
== _|_ {\n\trepoMessage: \"Fetching repository\"\n\treleaseMessage:
\"Wating repository ready\"\n}\nif context.output.status != _|_ {\n\trepoStatus:
context.output.status\n\tif repoStatus.conditions[0][\"type\"] != \"Ready\"
{\n\t\trepoMessage: \"Fetch repository fail\"\n\t}\n\tif repoStatus.conditions[0][\"type\"]
== \"Ready\" {\n\t\trepoMessage: \"Fetch repository successfully\"\n\t}\n\n\tif
context.outputs.release.status == _|_ {\n\t\treleaseMessage: \"Creating
helm release\"\n\t}\n\tif context.outputs.release.status != _|_ {\n\t\tif
context.outputs.release.status.conditions[0][\"message\"] == \"Release
reconciliation succeeded\" {\n\t\t\treleaseMessage: \"Create helm release
successfully\"\n\t\t}\n\t\tif context.outputs.release.status.conditions[0][\"message\"]
!= \"Release reconciliation succeeded\" {\n\t\t\treleaseBasicMessage:
\"Delivery helm release in progress, message: \" + context.outputs.release.status.conditions[0][\"message\"]\n\t\t\tif
len(context.outputs.release.status.conditions) == 1 {\n\t\t\t\treleaseMessage:
releaseBasicMessage\n\t\t\t}\n\t\t\tif len(context.outputs.release.status.conditions)
> 1 {\n\t\t\t\treleaseMessage: releaseBasicMessage + \", \" + context.outputs.release.status.conditions[1][\"message\"]\n\t\t\t}\n\t\t}\n\t}\n\n}\nmessage:
repoMessage + \", \" + releaseMessage"
healthPolicy: 'isHealth: len(context.outputs.release.status.conditions)
!= 0 && context.outputs.release.status.conditions[0]["status"]=="True"'
workload:
type: autodetects.core.oam.dev
- apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: A list of JSON6902 patch to selected target
name: kustomize-json-patch
namespace: {{.Values.systemDefinitionNamespace}}
spec:
schematic:
cue:
template: "patch: {\n\tspec: {\n\t\tpatchesJson6902: parameter.patchesJson\n\t}\n}\n\nparameter:
{\n\t// +usage=A list of JSON6902 patch.\n\tpatchesJson: [...#jsonPatchItem]\n}\n\n//
+usage=Contains a JSON6902 patch\n#jsonPatchItem: {\n\ttarget: #selector\n\tpatch:
[...{\n\t\t// +usage=operation to perform\n\t\top: string | \"add\"
| \"remove\" | \"replace\" | \"move\" | \"copy\" | \"test\"\n\t\t//
+usage=operate path e.g. /foo/bar\n\t\tpath: string\n\t\t// +usage=specify
source path when op is copy/move\n\t\tfrom?: string\n\t\t// +usage=specify
opraation value when op is test/add/replace\n\t\tvalue?: string\n\t}]\n}\n\n//
+usage=Selector specifies a set of resources\n#selector: {\n\tgroup?:
\ string\n\tversion?: string\n\tkind?: string\n\tnamespace?:
\ string\n\tname?: string\n\tannotationSelector?:
string\n\tlabelSelector?: string\n}\n"
- apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: A list of StrategicMerge or JSON6902 patch
to selected target
name: kustomize-patch
namespace: {{.Values.systemDefinitionNamespace}}
spec:
schematic:
cue:
template: "patch: {\n\tspec: {\n\t\tpatches: parameter.patches\n\t}\n}\nparameter:
{\n\t// +usage=a list of StrategicMerge or JSON6902 patch to selected
target\n\tpatches: [...#patchItem]\n}\n\n// +usage=Contains a strategicMerge
or JSON6902 patch\n#patchItem: {\n\t// +usage=Inline patch string,
in yaml style\n\tpatch: string\n\t// +usage=Specify the target the
patch should be applied to\n\ttarget: #selector\n}\n\n// +usage=Selector
specifies a set of resources\n#selector: {\n\tgroup?: string\n\tversion?:
\ string\n\tkind?: string\n\tnamespace?: string\n\tname?:
\ string\n\tannotationSelector?: string\n\tlabelSelector?:
\ string\n}\n"
- apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
annotations:
definition.oam.dev/description: kustomize can fetching, building, updating
and applying Kustomize manifests from git repo.
name: kustomize
namespace: {{.Values.systemDefinitionNamespace}}
spec:
schematic:
cue:
template: "output: {\n\tapiVersion: \"kustomize.toolkit.fluxcd.io/v1beta1\"\n\tkind:
\ \"Kustomization\"\n\tmetadata: {\n\t\tname: context.name\n
\ namespace: context.namespace\n\t}\n\tspec: {\n\t\tinterval: parameter.pullInterval\n\t\tsourceRef:
{\n\t\t\tif parameter.repoType == \"git\" {\n\t\t\t\tkind: \"GitRepository\"\n\t\t\t}\n\t\t\tif
parameter.repoType == \"oss\" {\n\t\t\t\tkind: \"Bucket\"\n\t\t\t}\n\t\t\tname:
\ context.name\n\t\t\tnamespace: context.namespace\n\t\t}\n\t\tpath:
\ parameter.path\n\t\tprune: true\n\t\tvalidation: \"client\"\n\t}\n}\n\noutputs:
{\n repo: {\n\t apiVersion: \"source.toolkit.fluxcd.io/v1beta1\"\n\t
\ metadata: {\n\t\t name: context.name\n namespace: context.namespace\n\t
\ }\n\t if parameter.repoType == \"git\" {\n\t\t kind: \"GitRepository\"\n\t\t
\ spec: {\n\t\t\t url: parameter.url\n\t\t\t if parameter.git.branch
!= _|_ {\n\t\t\t\t ref: branch: parameter.git.branch\n\t\t\t }\n
\ if parameter.git.provider != _|_ {\n if parameter.git.provider
== \"GitHub\" {\n gitImplementation: \"go-git\"\n }\n
\ if parameter.git.provider == \"AzureDevOps\" {\n gitImplementation:
\"libgit2\"\n }\n }\n\t\t\t _secret\n\t\t\t _sourceCommonArgs\n\t\t
\ }\n\t }\n\t if parameter.repoType == \"oss\" {\n\t\t kind: \"Bucket\"\n\t\t
\ spec: {\n\t\t\t endpoint: parameter.url\n\t\t\t bucketName:
parameter.oss.bucketName\n\t\t\t provider: parameter.oss.provider\n\t\t\t
\ if parameter.oss.region != _|_ {\n\t\t\t\t region: parameter.oss.region\n\t\t\t
\ }\n\t\t\t _secret\n\t\t\t _sourceCommonArgs\n\t\t }\n\t }\n
\ }\n\n if parameter.imageRepository != _|_ {\n imageRepo: {\n
\ apiVersion: \"image.toolkit.fluxcd.io/v1beta1\"\n kind:
\"ImageRepository\"\n\t metadata: {\n\t\t name: context.name\n
\ namespace: context.namespace\n\t }\n spec: {\n image:
parameter.imageRepository.image\n interval: parameter.pullInterval\n
\ if parameter.imageRepository.secretRef != _|_ {\n secretRef:
name: parameter.imageRepository.secretRef\n }\n }\n }\n\n
\ imagePolicy: {\n apiVersion: \"image.toolkit.fluxcd.io/v1beta1\"\n
\ kind: \"ImagePolicy\"\n\t metadata: {\n\t\t name: context.name\n
\ namespace: context.namespace\n\t }\n spec: {\n imageRepositoryRef:
name: context.name\n policy: parameter.imageRepository.policy\n
\ if parameter.imageRepository.filterTags != _|_ {\n filterTags:
parameter.imageRepository.filterTags\n }\n }\n }\n\n
\ imageUpdate: {\n apiVersion: \"image.toolkit.fluxcd.io/v1beta1\"\n
\ kind: \"ImageUpdateAutomation\"\n\t metadata: {\n\t\t name:
context.name\n namespace: context.namespace\n\t }\n spec:
{\n interval: parameter.pullInterval\n sourceRef: {\n
\ kind: \"GitRepository\"\n name: context.name\n
\ }\n git: {\n checkout: ref: branch: parameter.git.branch\n
\ commit: {\n author: {\n email: \"kubevelabot@users.noreply.github.com\"\n
\ name: \"kubevelabot\"\n }\n if
parameter.imageRepository.commitMessage != _|_ {\n messageTemplate:
\"Update image automatically.\\n\" + parameter.imageRepository.commitMessage\n
\ }\n if parameter.imageRepository.commitMessage
== _|_ {\n messageTemplate: \"Update image automatically.\"\n
\ }\n }\n push: branch: parameter.git.branch\n
\ }\n update: {\n path:\tparameter.path\n strategy:
\"Setters\"\n }\n }\n }\n }\n}\n\n_secret: {\n\tif
parameter.secretRef != _|_ {\n\t\tsecretRef: {\n\t\t\tname: parameter.secretRef\n\t\t}\n\t}\n}\n\n_sourceCommonArgs:
{\n\tinterval: parameter.pullInterval\n\tif parameter.timeout != _|_
{\n\t\ttimeout: parameter.timeout\n\t}\n}\n\nparameter: {\n\trepoType:
*\"git\" | \"oss\"\n // +usage=The image repository for automatically
update image to git\n imageRepository?: {\n // +usage=The image
url\n image: string\n // +usage=The name of the secret containing
authentication credentials\n secretRef?: string\n // +usage=Policy
gives the particulars of the policy to be followed in selecting the
most recent image.\n policy: {\n // +usage=Alphabetical set
of rules to use for alphabetical ordering of the tags.\n alphabetical?:
{\n // +usage=Order specifies the sorting order of the tags.\n
\ // +usage=Given the letters of the alphabet as tags, ascending
order would select Z, and descending order would select A.\n order?:
\"asc\" | \"desc\"\n }\n // +usage=Numerical set of rules
to use for numerical ordering of the tags.\n numerical?: {\n
\ // +usage=Order specifies the sorting order of the tags.\n
\ // +usage=Given the integer values from 0 to 9 as tags, ascending
order would select 9, and descending order would select 0.\n order:
\"asc\" | \"desc\"\n }\n // +usage=SemVer gives a semantic
version range to check against the tags available.\n semver?:
{\n // +usage=Range gives a semver range for the image tag;
the highest version within the range that's a tag yields the latest
image.\n range: string\n }\n }\n // +usage=FilterTags
enables filtering for only a subset of tags based on a set of rules.
If no rules are provided, all the tags from the repository will be
ordered and compared.\n filterTags?: {\n // +usage=Extract
allows a capture group to be extracted from the specified regular
expression pattern, useful before tag evaluation.\n extract?:
string\n // +usage=Pattern specifies a regular expression pattern
used to filter for image tags.\n pattern?: string\n }\n //
+usage=The image url\n commitMessage?: string\n }\n\t// +usage=The
interval at which to check for repository/bucket and release updates,
default to 5m\n\tpullInterval: *\"5m\" | string\n\t// +usage=The Git
or Helm repository URL, OSS endpoint, accept HTTP/S or SSH address
as git url,\n\turl: string\n\t// +usage=The name of the secret containing
authentication credentials\n\tsecretRef?: string\n\t// +usage=The
timeout for operations like download index/clone repository, optional\n\ttimeout?:
string\n\tgit?: {\n\t\t// +usage=The Git reference to checkout and
monitor for changes, defaults to master branch\n\t\tbranch: string\n
\ // +usage=Determines which git client library to use. Defaults
to GitHub, it will pick go-git. AzureDevOps will pick libgit2.\n provider?:
*\"GitHub\" | \"AzureDevOps\"\n\t}\n\toss?: {\n\t\t// +usage=The bucket's
name, required if repoType is oss\n\t\tbucketName: string\n\t\t//
+usage=\"generic\" for Minio, Amazon S3, Google Cloud Storage, Alibaba
Cloud OSS, \"aws\" for retrieve credentials from the EC2 service when
credentials not specified, default \"generic\"\n\t\tprovider: *\"generic\"
| \"aws\"\n\t\t// +usage=The bucket region, optional\n\t\tregion?:
string\n\t}\n\t//+usage=Path to the directory containing the kustomization.yaml
file, or the set of plain YAMLs a kustomization.yaml should be generated
for.\n\tpath: string\n}"
workload:
type: autodetects.core.oam.dev
- apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: A list of strategic merge to kustomize
config
name: kustomize-strategy-merge
namespace: {{.Values.systemDefinitionNamespace}}
spec:
schematic:
cue:
template: "patch: {\n\tspec: {\n\t\tpatchesStrategicMerge: parameter.patchesStrategicMerge\n\t}\n}\n\nparameter:
{\n\t// +usage=a list of strategicmerge, defined as inline yaml objects.\n\tpatchesStrategicMerge:
[...#nestedmap]\n}\n\n#nestedmap: {\n\t...\n}\n"
type: k8s-objects
{{- end }}
File diff suppressed because it is too large Load Diff
@@ -2,7 +2,7 @@ apiVersion: v1
kind: ConfigMap
metadata:
name: vela-addon-registry
namespace: {{ include "systemDefinitionNamespace" . }}
namespace: {{ .Release.Namespace }}
data:
registries: '{
"KubeVela":{
+3 -1
View File
@@ -136,4 +136,6 @@ test:
tag: v1
k8s:
repository: oamdev/alpine-k8s
tag: 1.18.2
tag: 1.18.2
enableFluxcdAddon: false
+21
View File
@@ -80,6 +80,27 @@ var _ = Describe("Addon Test", func() {
}, 60*time.Second).Should(Succeed())
})
It("Test Change default namespace can work", func() {
output, err := e2e.LongTimeExecWithEnv("vela addon list", 600*time.Second, []string{"DEFAULT_VELA_NS=test-vela"})
Expect(err).NotTo(HaveOccurred())
Expect(output).To(ContainSubstring("test-addon"))
Expect(output).To(ContainSubstring("disabled"))
output, err = e2e.LongTimeExecWithEnv("vela addon enable test-addon", 600*time.Second, []string{"DEFAULT_VELA_NS=test-vela"})
Expect(err).NotTo(HaveOccurred())
Expect(output).To(ContainSubstring("enabled Successfully."))
Eventually(func(g Gomega) {
g.Expect(k8sClient.Get(context.Background(), types.NamespacedName{Name: "addon-test-addon", Namespace: "test-vela"}, &v1beta1.Application{})).Should(BeNil())
}, 60*time.Second).Should(Succeed())
output, err = e2e.LongTimeExecWithEnv("vela addon disable test-addon", 600*time.Second, []string{"DEFAULT_VELA_NS=test-vela"})
Expect(err).NotTo(HaveOccurred())
Expect(output).To(ContainSubstring("Successfully disable addon"))
Eventually(func(g Gomega) {
g.Expect(apierrors.IsNotFound(k8sClient.Get(context.Background(), types.NamespacedName{Name: "addon-test-addon", Namespace: "test-vela"}, &v1beta1.Application{}))).Should(BeTrue())
}, 60*time.Second).Should(Succeed())
})
})
Context("Addon registry test", func() {
+18 -3
View File
@@ -21,6 +21,8 @@ import (
"fmt"
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/yaml"
@@ -63,12 +65,25 @@ func ApplyMockServerConfig() error {
return err
}
otherRegistry := cm.DeepCopy()
err = k8sClient.Get(ctx, types.NamespacedName{Name: cm.Name, Namespace: cm.Namespace}, &originCm)
if err != nil && apierrors.IsNotFound(err) {
err = k8sClient.Create(ctx, &cm)
if err = k8sClient.Create(ctx, &cm); err != nil {
return err
}
} else {
cm.ResourceVersion = originCm.ResourceVersion
err = k8sClient.Update(ctx, &cm)
if err = k8sClient.Update(ctx, &cm); err != nil {
return err
}
}
return err
if err := k8sClient.Create(ctx, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-vela"}}); err != nil {
return err
}
otherRegistry.SetNamespace("test-vela")
if err := k8sClient.Create(ctx, otherRegistry); err != nil {
return err
}
return nil
}
+16
View File
@@ -80,6 +80,22 @@ func asyncExec(cli string) (*gexec.Session, error) {
return session, err
}
func LongTimeExecWithEnv(cli string, timeout time.Duration, env []string) (string, error) {
var output []byte
c := strings.Fields(cli)
commandName := path.Join(rudrPath, c[0])
command := exec.Command(commandName, c[1:]...)
command.Env = os.Environ()
command.Env = append(command.Env, env...)
session, err := gexec.Start(command, ginkgo.GinkgoWriter, ginkgo.GinkgoWriter)
if err != nil {
return string(output), err
}
s := session.Wait(timeout)
return string(s.Out.Contents()) + string(s.Err.Contents()), nil
}
// InteractiveExec executes a command with interactive input
func InteractiveExec(cli string, consoleFn func(*expect.Console)) (string, error) {
var output []byte
+43 -37
View File
@@ -466,6 +466,10 @@ func RenderApp(ctx context.Context, addon *InstallPackage, config *rest.Config,
}
}
app.Labels = util.MergeMapOverrideWithDst(app.Labels, map[string]string{oam.LabelAddonName: addon.Name})
// force override the namespace defined vela with DefaultVelaNS,this value can be modified by Env
app.SetNamespace(types.DefaultKubeVelaNS)
for _, namespace := range addon.NeedNamespace {
// vela-system must exist before rendering vela addon
if namespace == types.DefaultKubeVelaNS {
@@ -479,13 +483,14 @@ func RenderApp(ctx context.Context, addon *InstallPackage, config *rest.Config,
app.Spec.Components = append(app.Spec.Components, comp)
}
for _, tmpl := range addon.YAMLTemplates {
comp, err := renderRawComponent(tmpl)
if len(addon.YAMLTemplates) != 0 {
comp, err := renderK8sObjectsComponent(addon.YAMLTemplates, addon.Name)
if err != nil {
return nil, err
}
app.Spec.Components = append(app.Spec.Components, *comp)
}
for _, tmpl := range addon.CUETemplates {
comp, err := renderCUETemplate(tmpl, addon.Parameters, args)
if err != nil {
@@ -546,13 +551,6 @@ func RenderApp(ctx context.Context, addon *InstallPackage, config *rest.Config,
app.Spec.Workflow.Steps = append(app.Spec.Workflow.Steps, workflowSteps...)
default:
for _, def := range addon.Definitions {
comp, err := renderRawComponent(def)
if err != nil {
return nil, err
}
app.Spec.Components = append(app.Spec.Components, *comp)
}
for _, cueDef := range addon.CUEDefinitions {
def := definition.Definition{Unstructured: unstructured.Unstructured{}}
err := def.FromCUEString(cueDef.Data, config)
@@ -592,28 +590,28 @@ func RenderApp(ctx context.Context, addon *InstallPackage, config *rest.Config,
func RenderDefinitions(addon *InstallPackage, config *rest.Config) ([]*unstructured.Unstructured, error) {
defObjs := make([]*unstructured.Unstructured, 0)
if isDeployToRuntimeOnly(addon) {
// Runtime cluster mode needs to deploy definitions to control plane k8s.
for _, def := range addon.Definitions {
obj, err := renderObject(def)
if err != nil {
return nil, err
}
defObjs = append(defObjs, obj)
}
for _, cueDef := range addon.CUEDefinitions {
def := definition.Definition{Unstructured: unstructured.Unstructured{}}
err := def.FromCUEString(cueDef.Data, config)
if err != nil {
return nil, errors.Wrapf(err, "fail to render definition: %s in cue's format", cueDef.Name)
}
if def.GetNamespace() == "" {
def.SetNamespace(types.DefaultKubeVelaNS)
}
defObjs = append(defObjs, &def.Unstructured)
// No matter runtime mode or control mode , definition only needs to control plane k8s.
for _, def := range addon.Definitions {
obj, err := renderObject(def)
if err != nil {
return nil, err
}
// we should ignore the namespace defined in definition yaml, override the filed by DefaultKubeVelaNS
obj.SetNamespace(types.DefaultKubeVelaNS)
defObjs = append(defObjs, obj)
}
for _, cueDef := range addon.CUEDefinitions {
def := definition.Definition{Unstructured: unstructured.Unstructured{}}
err := def.FromCUEString(cueDef.Data, config)
if err != nil {
return nil, errors.Wrapf(err, "fail to render definition: %s in cue's format", cueDef.Name)
}
// we should ignore the namespace defined in definition yaml, override the filed by DefaultKubeVelaNS
def.SetNamespace(types.DefaultKubeVelaNS)
defObjs = append(defObjs, &def.Unstructured)
}
return defObjs, nil
}
@@ -741,17 +739,25 @@ func renderNamespace(namespace string) *unstructured.Unstructured {
return u
}
// renderRawComponent will return a component in raw type from string
func renderRawComponent(elem ElementFile) (*common2.ApplicationComponent, error) {
baseRawComponent := common2.ApplicationComponent{
Type: "raw",
Name: strings.ReplaceAll(elem.Name, ".", "-"),
func renderK8sObjectsComponent(elems []ElementFile, addonName string) (*common2.ApplicationComponent, error) {
var objects []*unstructured.Unstructured
for _, elem := range elems {
obj, err := renderObject(elem)
if err != nil {
return nil, err
}
objects = append(objects, obj)
}
obj, err := renderObject(elem)
properties := map[string]interface{}{"objects": objects}
propJSON, err := json.Marshal(properties)
if err != nil {
return nil, err
}
baseRawComponent.Properties = util.Object2RawExtension(obj)
baseRawComponent := common2.ApplicationComponent{
Type: "k8s-objects",
Name: addonName + "-resources",
Properties: &runtime.RawExtension{Raw: propJSON},
}
return &baseRawComponent, nil
}
@@ -985,7 +991,7 @@ func (h *Installer) dispatchAddonResource(addon *InstallPackage) error {
app.SetLabels(util.MergeMapOverrideWithDst(app.GetLabels(), map[string]string{oam.LabelAddonRegistry: h.r.Name}))
defs, err := RenderDefinitions(h.addon, h.config)
defs, err := RenderDefinitions(addon, h.config)
if err != nil {
return errors.Wrap(err, "render addon definitions fail")
}
+96
View File
@@ -258,6 +258,39 @@ func TestRenderDeploy2RuntimeAddon(t *testing.T) {
assert.Equal(t, steps[len(steps)-1].Type, "deploy2runtime")
}
func TestRenderDefinitions(t *testing.T) {
addonDeployToRuntime := baseAddon
addonDeployToRuntime.Meta.DeployTo = &DeployTo{
DisableControlPlane: false,
RuntimeCluster: false,
}
defs, err := RenderDefinitions(&addonDeployToRuntime, nil)
assert.NoError(t, err)
assert.Equal(t, len(defs), 1)
def := defs[0]
assert.Equal(t, def.GetAPIVersion(), "core.oam.dev/v1beta1")
assert.Equal(t, def.GetKind(), "TraitDefinition")
app, err := RenderApp(ctx, &addonDeployToRuntime, nil, 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)
}
func TestRenderK8sObjects(t *testing.T) {
addonMultiYaml := multiYamlAddon
addonMultiYaml.Meta.DeployTo = &DeployTo{
DisableControlPlane: false,
RuntimeCluster: false,
}
app, err := RenderApp(ctx, &addonMultiYaml, nil, nil, map[string]interface{}{})
assert.NoError(t, err)
assert.Equal(t, len(app.Spec.Components), 1)
comp := app.Spec.Components[0]
assert.Equal(t, comp.Type, "k8s-objects")
}
func TestGetAddonStatus(t *testing.T) {
getFunc := test.MockGetFn(func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
switch key.Name {
@@ -402,6 +435,22 @@ var baseAddon = InstallPackage{
},
}
var multiYamlAddon = InstallPackage{
Meta: Meta{
Name: "test-render-multi-yaml-addon",
},
YAMLTemplates: []ElementFile{
{
Data: testYamlObject1,
Name: "test-object-1",
},
{
Data: testYamlObject2,
Name: "test-object-2",
},
},
}
var testCueDef = `annotations: {
type: "trait"
annotations: {}
@@ -433,6 +482,53 @@ template: {
}
`
var testYamlObject1 = `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
`
var testYamlObject2 = `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-2
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
`
func TestRenderApp4Observability(t *testing.T) {
k8sClient := fake.NewClientBuilder().Build()
testcases := []struct {
+6
View File
@@ -21,6 +21,8 @@ import (
"os"
"time"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/references/a/preimport"
"github.com/oam-dev/kubevela/references/cli"
)
@@ -29,6 +31,10 @@ func main() {
preimport.ResumeLogging()
rand.Seed(time.Now().UnixNano())
if ns := os.Getenv("DEFAULT_VELA_NS"); len(ns) != 0 {
types.DefaultKubeVelaNS = ns
}
command := cli.NewCommand()
if err := command.Execute(); err != nil {