From 35ae4e5ef5fe951bd7ec4c4ed89d457bc3264e89 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 25 Jul 2022 17:02:32 +0800 Subject: [PATCH] [Backport release-1.5] Fix: address failure when rendering addon API schemas (#4445) * Fix: address failure when rendering addon API schemas Signed-off-by: Charlie Chiang (cherry picked from commit de7a64346cfe1c17c3a3f9a0ecbcef2a644dacce) * Fix: address failure when rendering addon API schemas Signed-off-by: Charlie Chiang (cherry picked from commit 284e673badf0f8cee8adb845cd14203a81a35ffd) * Test: add tests Signed-off-by: Charlie Chiang (cherry picked from commit 1c0653e44999d2e074fceaa1ef3aa12d029f74e8) * Test: fix tests Signed-off-by: Charlie Chiang (cherry picked from commit 78104068b1613ba56a20759f15529d01e1824b2a) * Test: fix tests Signed-off-by: Charlie Chiang (cherry picked from commit 0442f823c8bfa121efd06deb07200dfeb54a7349) Co-authored-by: Charlie Chiang --- pkg/addon/addon.go | 9 ++- pkg/addon/addon_test.go | 34 ++++++++-- pkg/addon/helper_test.go | 1 + pkg/addon/render.go | 2 +- pkg/addon/testdata/example-legacy/Chart.yaml | 12 ++++ .../example-legacy/definitions/dummy.txt | 0 .../example-legacy/definitions/helm.yaml | 62 +++++++++++++++++++ .../testdata/example-legacy/metadata.yaml | 23 +++++++ pkg/addon/testdata/example-legacy/readme.md | 19 ++++++ .../example-legacy/resources/configmap.cue | 15 +++++ .../example-legacy/resources/dummy.txt | 0 .../resources/parameter.cue | 0 .../resources/service/source-controller.yaml | 17 +++++ .../{example => example-legacy}/template.yaml | 2 +- pkg/addon/testdata/example/parameter.cue | 3 + pkg/addon/testdata/example/template.cue | 27 ++++++++ 16 files changed, 215 insertions(+), 11 deletions(-) create mode 100644 pkg/addon/testdata/example-legacy/Chart.yaml create mode 100644 pkg/addon/testdata/example-legacy/definitions/dummy.txt create mode 100644 pkg/addon/testdata/example-legacy/definitions/helm.yaml create mode 100644 pkg/addon/testdata/example-legacy/metadata.yaml create mode 100644 pkg/addon/testdata/example-legacy/readme.md create mode 100644 pkg/addon/testdata/example-legacy/resources/configmap.cue create mode 100644 pkg/addon/testdata/example-legacy/resources/dummy.txt rename pkg/addon/testdata/{example => example-legacy}/resources/parameter.cue (100%) create mode 100644 pkg/addon/testdata/example-legacy/resources/service/source-controller.yaml rename pkg/addon/testdata/{example => example-legacy}/template.yaml (95%) create mode 100644 pkg/addon/testdata/example/parameter.cue create mode 100644 pkg/addon/testdata/example/template.cue diff --git a/pkg/addon/addon.go b/pkg/addon/addon.go index d1b112a1f..746c40ced 100644 --- a/pkg/addon/addon.go +++ b/pkg/addon/addon.go @@ -306,13 +306,16 @@ func GetUIDataFromReader(r AsyncReader, meta *SourceMeta, opt ListOptions) (*UID } if opt.GetParameter && (len(addon.Parameters) != 0 || len(addon.GlobalParameters) != 0) { + if addon.GlobalParameters != "" { + if addon.Parameters != "" { + klog.Warning("both legacy parameter and global parameter are provided, but only global parameter will be used. Consider removing the legacy parameters.") + } + addon.Parameters = addon.GlobalParameters + } err := genAddonAPISchema(addon) if err != nil { return nil, fmt.Errorf("fail to generate openAPIschema for addon %s : %w", meta.Name, err) } - if len(addon.GlobalParameters) != 0 { - addon.Parameters = addon.GlobalParameters - } } addon.AvailableVersions = []string{addon.Version} return addon, nil diff --git a/pkg/addon/addon_test.go b/pkg/addon/addon_test.go index 576133471..1ef8e5614 100644 --- a/pkg/addon/addon_test.go +++ b/pkg/addon/addon_test.go @@ -58,12 +58,20 @@ import ( var paths = []string{ "example/metadata.yaml", "example/readme.md", - "example/template.yaml", + "example/template.cue", "example/definitions/helm.yaml", "example/resources/configmap.cue", - "example/resources/parameter.cue", + "example/parameter.cue", "example/resources/service/source-controller.yaml", + "example-legacy/metadata.yaml", + "example-legacy/readme.md", + "example-legacy/template.yaml", + "example-legacy/definitions/helm.yaml", + "example-legacy/resources/configmap.cue", + "example-legacy/resources/parameter.cue", + "example-legacy/resources/service/source-controller.yaml", + "terraform/metadata.yaml", "terraform-alibaba/metadata.yaml", @@ -159,11 +167,25 @@ func testReaderFunc(t *testing.T, reader AsyncReader) { assert.True(t, uiData.Parameters != "") assert.True(t, len(uiData.Definitions) > 0) + testAddonName = "example-legacy" + for _, m := range registryMeta { + if m.Name == testAddonName { + testAddonMeta = m + break + } + } + assert.NoError(t, err) + uiData, err = GetUIDataFromReader(reader, &testAddonMeta, UIMetaOptions) + assert.NoError(t, err) + assert.Equal(t, uiData.Name, testAddonName) + assert.True(t, uiData.Parameters != "") + assert.True(t, len(uiData.Definitions) > 0) + // test get ui data rName := "KubeVela" uiDataList, err := ListAddonUIDataFromReader(reader, registryMeta, rName, UIMetaOptions) assert.True(t, strings.Contains(err.Error(), "#parameter.example: preference mark not allowed at this position")) - assert.Equal(t, 4, len(uiDataList)) + assert.Equal(t, 5, len(uiDataList)) assert.Equal(t, uiDataList[0].RegistryName, rName) // test get install package @@ -1151,13 +1173,13 @@ func TestCheckEnableAddonErrorWhenMissMatch(t *testing.T) { func TestPackageAddon(t *testing.T) { pwd, _ := os.Getwd() - validAddonDict := "./testdata/example" + validAddonDict := "./testdata/example-legacy" archiver, err := PackageAddon(validAddonDict) assert.NoError(t, err) - assert.Equal(t, filepath.Join(pwd, "example-1.0.1.tgz"), archiver) + assert.Equal(t, filepath.Join(pwd, "example-legacy-1.0.1.tgz"), archiver) // Remove generated package after tests defer func() { - _ = os.RemoveAll(filepath.Join(pwd, "example-1.0.1.tgz")) + _ = os.RemoveAll(filepath.Join(pwd, "example-legacy-1.0.1.tgz")) }() invalidAddonDict := "./testdata" diff --git a/pkg/addon/helper_test.go b/pkg/addon/helper_test.go index de305dbac..616a9bf93 100644 --- a/pkg/addon/helper_test.go +++ b/pkg/addon/helper_test.go @@ -141,6 +141,7 @@ var _ = Describe("test FindWholeAddonPackagesFromRegistry", func() { cmYaml := strings.ReplaceAll(registryCmYaml, "TEST_SERVER_URL", server.URL) cmYaml = strings.ReplaceAll(cmYaml, "KubeVela", "testreg") Expect(yaml.Unmarshal([]byte(cmYaml), &cm)).Should(BeNil()) + _ = k8sClient.Create(ctx, &cm) Expect(k8sClient.Update(ctx, &cm)).Should(BeNil()) }) diff --git a/pkg/addon/render.go b/pkg/addon/render.go index 957fd8c65..80a9b0e15 100644 --- a/pkg/addon/render.go +++ b/pkg/addon/render.go @@ -146,7 +146,7 @@ func renderCompAccordingCUETemplate(cueTemplate ElementFile, addon *InstallPacka inputArgs: args, } if err := r.toObject(cueTemplate.Data, &comp); err != nil { - return nil, err + return nil, fmt.Errorf("error rendering file %s: %w", cueTemplate.Name, err) } // If the name of component has been set, just keep it, otherwise will set with file name. if len(comp.Name) == 0 { diff --git a/pkg/addon/testdata/example-legacy/Chart.yaml b/pkg/addon/testdata/example-legacy/Chart.yaml new file mode 100644 index 000000000..5e084db19 --- /dev/null +++ b/pkg/addon/testdata/example-legacy/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +appVersion: 1.0.1 +description: Extended workload to do continuous and progressive delivery +home: https://fluxcd.io +icon: https://raw.githubusercontent.com/fluxcd/flux/master/docs/_files/weave-flux.png +keywords: +- extended_workload +- gitops +- only_example +name: example-legacy +type: library +version: 1.0.1 diff --git a/pkg/addon/testdata/example-legacy/definitions/dummy.txt b/pkg/addon/testdata/example-legacy/definitions/dummy.txt new file mode 100644 index 000000000..e69de29bb diff --git a/pkg/addon/testdata/example-legacy/definitions/helm.yaml b/pkg/addon/testdata/example-legacy/definitions/helm.yaml new file mode 100644 index 000000000..75150f08c --- /dev/null +++ b/pkg/addon/testdata/example-legacy/definitions/helm.yaml @@ -0,0 +1,62 @@ +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-example + namespace: vela-system +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\tinterval: parameter.pullInterval\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\tnamespace: context.namespace\n\t\t\t\t}\n\t\t\t\tinterval: + parameter.pullInterval\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\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\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: + healthPolicy: 'isHealth: len(context.outputs.release.status.conditions) + != 0 && context.outputs.release.status.conditions[0]["status"]=="True"' + workload: + type: autodetects.core.oam.dev diff --git a/pkg/addon/testdata/example-legacy/metadata.yaml b/pkg/addon/testdata/example-legacy/metadata.yaml new file mode 100644 index 000000000..769de99da --- /dev/null +++ b/pkg/addon/testdata/example-legacy/metadata.yaml @@ -0,0 +1,23 @@ +name: example-legacy +version: 1.0.1 +description: Extended workload to do continuous and progressive delivery +icon: https://raw.githubusercontent.com/fluxcd/flux/master/docs/_files/weave-flux.png +url: https://fluxcd.io + +tags: + - extended_workload + - gitops + - only_example + +deployTo: + control_plane: true + runtime_cluster: false + +dependencies: [] +#- name: addon_name + +# set invisible means this won't be list and will be enabled when depended on +# for example, terraform-alibaba depends on terraform which is invisible, +# when terraform-alibaba is enabled, terraform will be enabled automatically +# default: false +invisible: false diff --git a/pkg/addon/testdata/example-legacy/readme.md b/pkg/addon/testdata/example-legacy/readme.md new file mode 100644 index 000000000..aafc29dfe --- /dev/null +++ b/pkg/addon/testdata/example-legacy/readme.md @@ -0,0 +1,19 @@ +# Example FluxCD Addon + +This is an example addon based [FluxCD](https://fluxcd.io/) + +## Directory Structure + +- `template.yaml`: contains the basic app, you can add some component and workflow to meet your requirements. Other files + in `resources/` and `definitions/` will be rendered as Components and appended in `spec.components` +- `metadata.yaml`: contains addon metadata information. +- `definitions/`: contains the X-Definition yaml/cue files. These file will be rendered as KubeVela Component in `template.yaml` +- `resources/`: + - `parameter.cue` to expose parameters. It will be converted to JSON schema and rendered in UI forms. + - All other files will be rendered as KubeVela Components. It can be one of the two types: + - YAML file that contains only one resource. This will be rendered as a `raw` component + - CUE template file that can read user input as `parameter.XXX` as defined `parameter.cue`. + Basically the CUE template file will be combined with `parameter.cue` to render a resource. + **You can specify the type and trait in this format** + + diff --git a/pkg/addon/testdata/example-legacy/resources/configmap.cue b/pkg/addon/testdata/example-legacy/resources/configmap.cue new file mode 100644 index 000000000..cc3729d35 --- /dev/null +++ b/pkg/addon/testdata/example-legacy/resources/configmap.cue @@ -0,0 +1,15 @@ +output: { + type: "raw" + properties: { + apiVersion: "v1" + kind: "ConfigMap" + metadata: { + name: "exampleinput" + namespace: "default" + labels: { + version: context.metadata.version + } + } + data: input: parameter.example + } +} diff --git a/pkg/addon/testdata/example-legacy/resources/dummy.txt b/pkg/addon/testdata/example-legacy/resources/dummy.txt new file mode 100644 index 000000000..e69de29bb diff --git a/pkg/addon/testdata/example/resources/parameter.cue b/pkg/addon/testdata/example-legacy/resources/parameter.cue similarity index 100% rename from pkg/addon/testdata/example/resources/parameter.cue rename to pkg/addon/testdata/example-legacy/resources/parameter.cue diff --git a/pkg/addon/testdata/example-legacy/resources/service/source-controller.yaml b/pkg/addon/testdata/example-legacy/resources/service/source-controller.yaml new file mode 100644 index 000000000..999f4c4d8 --- /dev/null +++ b/pkg/addon/testdata/example-legacy/resources/service/source-controller.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/instance: flux-system + control-plane: controller + name: source-controller + namespace: example-system +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: http + selector: + app: source-controller + type: ClusterIP diff --git a/pkg/addon/testdata/example/template.yaml b/pkg/addon/testdata/example-legacy/template.yaml similarity index 95% rename from pkg/addon/testdata/example/template.yaml rename to pkg/addon/testdata/example-legacy/template.yaml index 069cec1a2..b34f2b0ed 100644 --- a/pkg/addon/testdata/example/template.yaml +++ b/pkg/addon/testdata/example-legacy/template.yaml @@ -1,7 +1,7 @@ apiVersion: core.oam.dev/v1beta1 kind: Application metadata: - name: example + name: example-legacy namespace: vela-system spec: workflow: diff --git a/pkg/addon/testdata/example/parameter.cue b/pkg/addon/testdata/example/parameter.cue new file mode 100644 index 000000000..2b0222f39 --- /dev/null +++ b/pkg/addon/testdata/example/parameter.cue @@ -0,0 +1,3 @@ +parameter: { + example: string +} \ No newline at end of file diff --git a/pkg/addon/testdata/example/template.cue b/pkg/addon/testdata/example/template.cue new file mode 100644 index 000000000..4b4552940 --- /dev/null +++ b/pkg/addon/testdata/example/template.cue @@ -0,0 +1,27 @@ +output: { + apiVersion: "core.oam.dev/v1beta1" + kind: "Application" + metadata: { + name: "example" + namespace: "vela-system" + } + spec: { + workflow: steps: [{ + name: "apply-ns" + type: "apply-component" + properties: component: "ns-example-system" + }, { + name: "apply-resources" + type: "apply-remaining" + }] + components: [{ + name: "ns-example-system" + type: "raw" + properties: { + apiVersion: "v1" + kind: "Namespace" + metadata: name: "example-system" + } + }] + } +}