From ce75a33633dbaea1a9b59d28be3c01157fa6f3b9 Mon Sep 17 00:00:00 2001 From: Jianbo Sun Date: Wed, 16 Nov 2022 16:00:29 +0800 Subject: [PATCH] Feat: support dry-run with cue format definition Signed-off-by: Jianbo Sun --- references/cli/dryrun.go | 39 +++++++++++---- references/cli/dryrun_test.go | 14 ++++++ references/cli/livediff.go | 2 +- references/cli/test-data/dry-run/app.yaml | 8 ++++ references/cli/test-data/dry-run/my-comp.cue | 50 ++++++++++++++++++++ 5 files changed, 104 insertions(+), 9 deletions(-) create mode 100644 references/cli/test-data/dry-run/app.yaml create mode 100644 references/cli/test-data/dry-run/my-comp.cue diff --git a/references/cli/dryrun.go b/references/cli/dryrun.go index c90ccb051..b3519b451 100644 --- a/references/cli/dryrun.go +++ b/references/cli/dryrun.go @@ -22,6 +22,7 @@ import ( "encoding/json" "os" "path/filepath" + "strings" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -32,6 +33,7 @@ import ( corev1beta1 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" "github.com/oam-dev/kubevela/apis/types" "github.com/oam-dev/kubevela/pkg/appfile/dryrun" + pkgdef "github.com/oam-dev/kubevela/pkg/definition" "github.com/oam-dev/kubevela/pkg/oam" "github.com/oam-dev/kubevela/pkg/oam/discoverymapper" oamutil "github.com/oam-dev/kubevela/pkg/oam/util" @@ -101,7 +103,7 @@ func DryRunApplication(cmdOption *DryRunCmdOptions, c common.Args, namespace str objs := []oam.Object{} if cmdOption.DefinitionFile != "" { - objs, err = ReadObjectsFromFile(cmdOption.DefinitionFile) + objs, err = ReadDefinitionsFromFile(cmdOption.DefinitionFile) if err != nil { return buff, err } @@ -160,15 +162,37 @@ func DryRunApplication(cmdOption *DryRunCmdOptions, c common.Args, namespace str return buff, nil } -// ReadObjectsFromFile will read objects from file or dir in the format of yaml -func ReadObjectsFromFile(path string) ([]oam.Object, error) { +func readObj(path string) (oam.Object, error) { + switch { + case strings.HasSuffix(path, ".cue"): + def := pkgdef.Definition{Unstructured: unstructured.Unstructured{}} + defBytes, err := os.ReadFile(filepath.Clean(path)) + if err != nil { + return nil, err + } + if err := def.FromCUEString(string(defBytes), nil); err != nil { + return nil, errors.Wrapf(err, "failed to parse CUE for definition") + } + obj := &unstructured.Unstructured{Object: def.UnstructuredContent()} + return obj, nil + default: + obj := &unstructured.Unstructured{} + err := common.ReadYamlToObject(path, obj) + if err != nil { + return nil, err + } + return obj, nil + } +} + +// ReadDefinitionsFromFile will read objects from file or dir in the format of yaml +func ReadDefinitionsFromFile(path string) ([]oam.Object, error) { fi, err := os.Stat(path) if err != nil { return nil, err } if !fi.IsDir() { - obj := &unstructured.Unstructured{} - err = common.ReadYamlToObject(path, obj) + obj, err := readObj(path) if err != nil { return nil, err } @@ -186,11 +210,10 @@ func ReadObjectsFromFile(path string) ([]oam.Object, error) { continue } fileType := filepath.Ext(fi.Name()) - if fileType != ".yaml" && fileType != ".yml" { + if fileType != ".yaml" && fileType != ".yml" && fileType != ".cue" { continue } - obj := &unstructured.Unstructured{} - err = common.ReadYamlToObject(filepath.Join(path, fi.Name()), obj) + obj, err := readObj(filepath.Join(path, fi.Name())) if err != nil { return nil, err } diff --git a/references/cli/dryrun_test.go b/references/cli/dryrun_test.go index 52cd6b4ee..3d760308b 100644 --- a/references/cli/dryrun_test.go +++ b/references/cli/dryrun_test.go @@ -74,6 +74,20 @@ var _ = Describe("Test dry run with policy", func() { Expect(buff.String()).Should(ContainSubstring("- image: oamdev/hello-world:v2\n name: server-v2")) }) + It("Test dry run with cue component format", func() { + + c := common2.Args{} + c.SetConfig(cfg) + c.SetClient(k8sClient) + + opt := DryRunCmdOptions{ApplicationFile: "test-data/dry-run/app.yaml", DefinitionFile: "test-data/dry-run/my-comp.cue", OfflineMode: true} + buff, err := DryRunApplication(&opt, c, "") + Expect(err).Should(BeNil()) + Expect(buff.String()).Should(ContainSubstring("name: hello-world")) + Expect(buff.String()).Should(ContainSubstring("kind: Deployment")) + Expect(buff.String()).Should(ContainSubstring("name: hello-world-service")) + Expect(buff.String()).Should(ContainSubstring("kind: Service")) + }) }) var plcapp = `apiVersion: core.oam.dev/v1beta1 diff --git a/references/cli/livediff.go b/references/cli/livediff.go index ce569292d..c0aa49201 100644 --- a/references/cli/livediff.go +++ b/references/cli/livediff.go @@ -104,7 +104,7 @@ func LiveDiffApplication(cmdOption *LiveDiffCmdOptions, c common.Args) (bytes.Bu } objs := []oam.Object{} if cmdOption.DefinitionFile != "" { - objs, err = ReadObjectsFromFile(cmdOption.DefinitionFile) + objs, err = ReadDefinitionsFromFile(cmdOption.DefinitionFile) if err != nil { return buff, err } diff --git a/references/cli/test-data/dry-run/app.yaml b/references/cli/test-data/dry-run/app.yaml new file mode 100644 index 000000000..ceb91dde3 --- /dev/null +++ b/references/cli/test-data/dry-run/app.yaml @@ -0,0 +1,8 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: vela-app +spec: + components: + - name: express-server + type: my-comp diff --git a/references/cli/test-data/dry-run/my-comp.cue b/references/cli/test-data/dry-run/my-comp.cue new file mode 100644 index 000000000..8a9a98567 --- /dev/null +++ b/references/cli/test-data/dry-run/my-comp.cue @@ -0,0 +1,50 @@ +"my-comp": { + annotations: {} + attributes: workload: definition: { + apiVersion: "apps/v1" + kind: "Deployment" + } + description: "My component." + labels: {} + type: "component" +} +template: { + output: { + metadata: name: "hello-world" + spec: { + replicas: 1 + selector: matchLabels: "app.kubernetes.io/name": "hello-world" + template: { + metadata: labels: "app.kubernetes.io/name": "hello-world" + spec: containers: [{ + name: "hello-world" + image: "somefive/hello-world" + ports: [{ + name: "http" + containerPort: 80 + protocol: "TCP" + }] + }] + } + } + apiVersion: "apps/v1" + kind: "Deployment" + } + outputs: "hello-world-service": { + metadata: name: "hello-world-service" + spec: { + ports: [{ + name: "http" + protocol: "TCP" + port: 80 + targetPort: 8080 + }] + selector: app: "hello-world" + type: "LoadBalancer" + } + apiVersion: "v1" + kind: "Service" + } + parameter: {} + +}