diff --git a/pkg/appfile/dryrun/diff_test.go b/pkg/appfile/dryrun/diff_test.go index 7dc72c271cb..936074a6a68 100644 --- a/pkg/appfile/dryrun/diff_test.go +++ b/pkg/appfile/dryrun/diff_test.go @@ -23,8 +23,6 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - corev1 "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/types" "sigs.k8s.io/yaml" @@ -167,7 +165,6 @@ var _ = Describe("Test Live-Diff", func() { Expect(k8sClient.Create(context.Background(), un)).Should(Succeed()) } ctx := context.Background() - Expect(k8sClient.Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "vela-system"}})).Should(Succeed()) applyFile("diff-input-app-with-externals.yaml", "default") applyFile("diff-apprevision.yaml", "default") app := &v1beta1.Application{} @@ -190,7 +187,6 @@ var _ = Describe("Test Live-Diff", func() { Expect(runDiff()).Should(ContainSubstring("\"myworker\" not found")) applyFile("td-myingress.yaml", "vela-system") applyFile("cd-myworker.yaml", "vela-system") - applyFile("wd-deploy.yaml", "vela-system") applyFile("wd-ref-objects.yaml", "vela-system") Expect(runDiff()).Should(ContainSubstring("\"deploy-livediff-demo\" not found")) applyFile("external-workflow.yaml", "default") diff --git a/pkg/appfile/dryrun/dryrun.go b/pkg/appfile/dryrun/dryrun.go index a10b8bdfb17..19df2fd072f 100644 --- a/pkg/appfile/dryrun/dryrun.go +++ b/pkg/appfile/dryrun/dryrun.go @@ -24,6 +24,11 @@ import ( "os" "path/filepath" + "github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1" + "github.com/oam-dev/kubevela/pkg/policy/envbinding" + "github.com/oam-dev/kubevela/pkg/utils" + "github.com/oam-dev/kubevela/pkg/workflow/step" + "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -143,6 +148,7 @@ func (d *Option) ExecuteDryRun(ctx context.Context, application *v1beta1.Applica if appFile.Namespace == "" { appFile.Namespace = corev1.NamespaceDefault } + comps, err := appFile.GenerateComponentManifests() if err != nil { return nil, nil, errors.WithMessage(err, "cannot generate manifests from components and traits") @@ -206,3 +212,120 @@ func (d *Option) PrintDryRun(buff *bytes.Buffer, appName string, comps []*types. } return nil } + +// ExecuteDryRunWithPolicies is similar to ExecuteDryRun func, but considers deploy workflow step and topology+override policies +func (d *Option) ExecuteDryRunWithPolicies(ctx context.Context, application *v1beta1.Application, buff *bytes.Buffer) error { + + app := application.DeepCopy() + if app.Namespace == "" { + app.Namespace = corev1.NamespaceDefault + } else { + ctx = oamutil.SetNamespaceInCtx(ctx, app.Namespace) + } + parser := appfile.NewDryRunApplicationParser(d.Client, d.DiscoveryMapper, d.PackageDiscover, d.Auxiliaries) + af, err := parser.GenerateAppFileFromApp(ctx, app) + if err != nil { + return err + } + + deployWorkflowCount := 0 + for _, wfs := range af.WorkflowSteps { + if wfs.Type == step.DeployWorkflowStep { + deployWorkflowCount++ + deployWorkflowStepSpec := &step.DeployWorkflowStepSpec{} + if err := utils.StrictUnmarshal(wfs.Properties.Raw, deployWorkflowStepSpec); err != nil { + return err + } + + topologyPolicies, overridePolicies, err := filterPolicies(af.Policies, deployWorkflowStepSpec.Policies) + if err != nil { + return err + } + if len(topologyPolicies) > 0 { + for _, tp := range topologyPolicies { + patchedApp, err := patchApp(app, overridePolicies) + if err != nil { + return err + } + comps, pms, err := d.ExecuteDryRun(ctx, patchedApp) + if err != nil { + return err + } + err = d.PrintDryRun(buff, fmt.Sprintf("%s with topology %s", patchedApp.Name, tp.Name), comps, pms) + if err != nil { + return err + } + } + } else { + patchedApp, err := patchApp(app, overridePolicies) + if err != nil { + return err + } + comps, pms, err := d.ExecuteDryRun(ctx, patchedApp) + if err != nil { + return err + } + err = d.PrintDryRun(buff, fmt.Sprintf("%s only with override policies", patchedApp.Name), comps, pms) + if err != nil { + return err + } + } + } + } + + if deployWorkflowCount == 0 { + comps, pms, err := d.ExecuteDryRun(ctx, app) + if err != nil { + return err + } + err = d.PrintDryRun(buff, app.Name, comps, pms) + if err != nil { + return err + } + } + + return nil +} + +func filterPolicies(policies []v1beta1.AppPolicy, policyNames []string) ([]v1beta1.AppPolicy, []v1beta1.AppPolicy, error) { + policyMap := make(map[string]v1beta1.AppPolicy) + for _, policy := range policies { + policyMap[policy.Name] = policy + } + var topologyPolicies []v1beta1.AppPolicy + var overridePolicies []v1beta1.AppPolicy + for _, policyName := range policyNames { + if policy, found := policyMap[policyName]; found { + switch policy.Type { + case v1alpha1.TopologyPolicyType: + topologyPolicies = append(topologyPolicies, policy) + case v1alpha1.OverridePolicyType: + overridePolicies = append(overridePolicies, policy) + } + } else { + return nil, nil, errors.Errorf("policy %s not found", policyName) + } + } + return topologyPolicies, overridePolicies, nil +} + +func patchApp(application *v1beta1.Application, overridePolicies []v1beta1.AppPolicy) (*v1beta1.Application, error) { + app := application.DeepCopy() + for _, policy := range overridePolicies { + + if policy.Properties == nil { + return nil, fmt.Errorf("override policy %s must not have empty properties", policy.Name) + } + overrideSpec := &v1alpha1.OverridePolicySpec{} + if err := utils.StrictUnmarshal(policy.Properties.Raw, overrideSpec); err != nil { + return nil, errors.Wrapf(err, "failed to parse override policy %s", policy.Name) + } + overrideComps, err := envbinding.PatchComponents(app.Spec.Components, overrideSpec.Components, overrideSpec.Selector) + if err != nil { + return nil, errors.Wrapf(err, "failed to apply override policy %s", policy.Name) + } + app.Spec.Components = overrideComps + } + + return app, nil +} diff --git a/pkg/appfile/dryrun/dryrun_test.go b/pkg/appfile/dryrun/dryrun_test.go index 2f7409c1c10..498fc1a6883 100644 --- a/pkg/appfile/dryrun/dryrun_test.go +++ b/pkg/appfile/dryrun/dryrun_test.go @@ -17,8 +17,11 @@ limitations under the License. package dryrun import ( + "bytes" "context" "encoding/json" + "os" + "strings" "github.com/oam-dev/kubevela/apis/types" @@ -59,3 +62,108 @@ var _ = Describe("Test DryRun", func() { Expect(diff).Should(BeEmpty()) }) }) + +var _ = Describe("Test dry run with policies", func() { + It("Test dry run with override policy", func() { + + webservice, err := os.ReadFile("../../../charts/vela-core/templates/defwithtemplate/webservice.yaml") + Expect(err).Should(BeNil()) + webserviceYAML := strings.Replace(string(webservice), "{{ include \"systemDefinitionNamespace\" . }}", types.DefaultKubeVelaNS, 1) + wwd := v1beta1.ComponentDefinition{} + Expect(yaml.Unmarshal([]byte(webserviceYAML), &wwd)).Should(BeNil()) + Expect(k8sClient.Create(context.TODO(), &wwd)).Should(BeNil()) + + scaler, err := os.ReadFile("../../../charts/vela-core/templates/defwithtemplate/scaler.yaml") + Expect(err).Should(BeNil()) + scalerYAML := strings.Replace(string(scaler), "{{ include \"systemDefinitionNamespace\" . }}", types.DefaultKubeVelaNS, 1) + var td v1beta1.TraitDefinition + Expect(yaml.Unmarshal([]byte(scalerYAML), &td)).Should(BeNil()) + Expect(k8sClient.Create(context.TODO(), &td)).Should(BeNil()) + + appYAML := readDataFromFile("./testdata/testing-dry-run-1.yaml") + app := &v1beta1.Application{} + Expect(yaml.Unmarshal([]byte(appYAML), &app)).Should(BeNil()) + + var buff = bytes.Buffer{} + err = dryrunOpt.ExecuteDryRunWithPolicies(context.TODO(), app, &buff) + Expect(err).Should(BeNil()) + Expect(buff.String()).Should(ContainSubstring("# Application(testing-app with topology target-default)")) + Expect(buff.String()).Should(ContainSubstring("# Application(testing-app with topology target-prod)")) + Expect(buff.String()).Should(ContainSubstring("name: testing-dryrun")) + Expect(buff.String()).Should(ContainSubstring("kind: Deployment")) + Expect(buff.String()).Should(ContainSubstring("replicas: 1")) + Expect(buff.String()).Should(ContainSubstring("replicas: 3")) + Expect(buff.String()).Should(ContainSubstring("kind: Service")) + }) + + It("Test dry run only with override policy", func() { + + appYAML := readDataFromFile("./testdata/testing-dry-run-2.yaml") + app := &v1beta1.Application{} + Expect(yaml.Unmarshal([]byte(appYAML), &app)).Should(BeNil()) + + var buff = bytes.Buffer{} + err := dryrunOpt.ExecuteDryRunWithPolicies(context.TODO(), app, &buff) + Expect(err).Should(BeNil()) + Expect(buff.String()).Should(ContainSubstring("# Application(testing-app only with override policies)")) + Expect(buff.String()).Should(ContainSubstring("name: testing-dryrun")) + Expect(buff.String()).Should(ContainSubstring("kind: Deployment")) + Expect(buff.String()).Should(ContainSubstring("replicas: 3")) + Expect(buff.String()).Should(ContainSubstring("kind: Service")) + }) + + It("Test dry run without deploy workflow", func() { + + appYAML := readDataFromFile("./testdata/testing-dry-run-3.yaml") + app := &v1beta1.Application{} + Expect(yaml.Unmarshal([]byte(appYAML), &app)).Should(BeNil()) + + var buff = bytes.Buffer{} + err := dryrunOpt.ExecuteDryRunWithPolicies(context.TODO(), app, &buff) + Expect(err).Should(BeNil()) + Expect(buff.String()).Should(ContainSubstring("# Application(testing-app)")) + Expect(buff.String()).Should(ContainSubstring("name: testing-dryrun")) + Expect(buff.String()).Should(ContainSubstring("kind: Deployment")) + }) + + It("Test dry run without custom policy", func() { + + topo, err := os.ReadFile("./testdata/pd-mypolicy.yaml") + Expect(err).Should(BeNil()) + var pd v1beta1.PolicyDefinition + Expect(yaml.Unmarshal([]byte(topo), &pd)).Should(BeNil()) + Expect(k8sClient.Create(context.TODO(), &pd)).Should(BeNil()) + + appYAML := readDataFromFile("./testdata/testing-dry-run-4.yaml") + app := &v1beta1.Application{} + Expect(yaml.Unmarshal([]byte(appYAML), &app)).Should(BeNil()) + + var buff = bytes.Buffer{} + err = dryrunOpt.ExecuteDryRunWithPolicies(context.TODO(), app, &buff) + Expect(err).Should(BeNil()) + Expect(buff.String()).Should(ContainSubstring("# Application(testing-app) -- Component(testing-dryrun)")) + Expect(buff.String()).Should(ContainSubstring("# Application(testing-app) -- Policy(mypolicy)")) + Expect(buff.String()).Should(ContainSubstring("name: my-policy")) + }) + + It("Test dry run with trait", func() { + + nocalhost, err := os.ReadFile("../../../charts/vela-core/templates/defwithtemplate/nocalhost.yaml") + Expect(err).Should(BeNil()) + nocalhostYAML := strings.Replace(string(nocalhost), "{{ include \"systemDefinitionNamespace\" . }}", types.DefaultKubeVelaNS, 1) + var td v1beta1.TraitDefinition + Expect(yaml.Unmarshal([]byte(nocalhostYAML), &td)).Should(BeNil()) + Expect(k8sClient.Create(context.TODO(), &td)).Should(BeNil()) + + appYAML := readDataFromFile("./testdata/testing-dry-run-5.yaml") + app := &v1beta1.Application{} + Expect(yaml.Unmarshal([]byte(appYAML), &app)).Should(BeNil()) + + var buff = bytes.Buffer{} + err = dryrunOpt.ExecuteDryRunWithPolicies(context.TODO(), app, &buff) + Expect(err).Should(BeNil()) + Expect(buff.String()).Should(ContainSubstring("# Application(testing-app) -- Component(testing-dryrun)")) + Expect(buff.String()).Should(ContainSubstring("## From the trait nocalhost")) + Expect(buff.String()).Should(ContainSubstring("trait.oam.dev/type: nocalhost")) + }) +}) diff --git a/pkg/appfile/dryrun/suit_test.go b/pkg/appfile/dryrun/suit_test.go index 597b7577ce8..70444e8cdff 100644 --- a/pkg/appfile/dryrun/suit_test.go +++ b/pkg/appfile/dryrun/suit_test.go @@ -17,11 +17,19 @@ limitations under the License. package dryrun import ( + "context" "os" "path/filepath" "testing" "time" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/yaml" + + "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" + "github.com/oam-dev/kubevela/apis/types" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -103,6 +111,16 @@ var _ = BeforeSuite(func(done Done) { tdMyIngress, err := oamutil.Object2Unstructured(myingressDef) Expect(err).Should(BeNil()) + // create vela-system ns + Expect(k8sClient.Create(context.TODO(), &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: types.DefaultKubeVelaNS}})).Should(Succeed()) + // create deploy workflow step definition + deploy, err := os.ReadFile("./testdata/wd-deploy.yaml") + Expect(err).Should(BeNil()) + var wfsd v1beta1.WorkflowStepDefinition + Expect(yaml.Unmarshal([]byte(deploy), &wfsd)).Should(BeNil()) + wfsd.SetNamespace(types.DefaultKubeVelaNS) + Expect(k8sClient.Create(context.TODO(), &wfsd)).Should(BeNil()) + dryrunOpt = NewDryRunOption(k8sClient, cfg, dm, pd, []oam.Object{cdMyWorker, tdMyIngress}, false) diffOpt = &LiveDiffOption{DryRun: dryrunOpt, Parser: appfile.NewApplicationParser(k8sClient, dm, pd)} diff --git a/pkg/appfile/dryrun/testdata/pd-mypolicy.yaml b/pkg/appfile/dryrun/testdata/pd-mypolicy.yaml new file mode 100644 index 00000000000..caa8e39c1c6 --- /dev/null +++ b/pkg/appfile/dryrun/testdata/pd-mypolicy.yaml @@ -0,0 +1,22 @@ +# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file. +# Definition source cue file: vela-templates/definitions/internal/topology.cue +apiVersion: core.oam.dev/v1beta1 +kind: PolicyDefinition +metadata: + name: mypolicy + namespace: vela-system +spec: + schematic: + cue: + template: | + output: { + apiVersion: "testing/v1" + kind: "Policy" + policy: { + name: parameter.name + } + } + + parameter: { + name: string + } diff --git a/pkg/appfile/dryrun/testdata/testing-dry-run-1.yaml b/pkg/appfile/dryrun/testdata/testing-dry-run-1.yaml new file mode 100644 index 00000000000..c955771de54 --- /dev/null +++ b/pkg/appfile/dryrun/testdata/testing-dry-run-1.yaml @@ -0,0 +1,48 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: testing-app + namespace: default +spec: + components: + - name: testing-dryrun + type: webservice + properties: + image: oamdev/hello-world:v1 + ports: + - port: 8000 + expose: true + traits: + - type: scaler + properties: + replicas: 1 + policies: + - name: target-default + type: topology + properties: + clusters: [ "local" ] + namespace: "default" + - name: target-prod + type: topology + properties: + clusters: [ "local" ] + namespace: "prod" + - name: deploy-ha + type: override + properties: + components: + - type: webservice + traits: + - type: scaler + properties: + replicas: 3 + workflow: + steps: + - name: deploy2default + type: deploy + properties: + policies: [ "target-default" ] + - name: deploy2prod + type: deploy + properties: + policies: [ "target-prod", "deploy-ha" ] \ No newline at end of file diff --git a/pkg/appfile/dryrun/testdata/testing-dry-run-2.yaml b/pkg/appfile/dryrun/testdata/testing-dry-run-2.yaml new file mode 100644 index 00000000000..a36ac03f3dd --- /dev/null +++ b/pkg/appfile/dryrun/testdata/testing-dry-run-2.yaml @@ -0,0 +1,27 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: testing-app +spec: + components: + - name: testing-dryrun + type: webservice + properties: + image: oamdev/hello-world:v1 + ports: + - port: 8000 + expose: true + traits: + - type: scaler + properties: + replicas: 1 + policies: + - name: deploy-ha + type: override + properties: + components: + - type: webservice + traits: + - type: scaler + properties: + replicas: 3 diff --git a/pkg/appfile/dryrun/testdata/testing-dry-run-3.yaml b/pkg/appfile/dryrun/testdata/testing-dry-run-3.yaml new file mode 100644 index 00000000000..99732517a56 --- /dev/null +++ b/pkg/appfile/dryrun/testdata/testing-dry-run-3.yaml @@ -0,0 +1,15 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: testing-app +spec: + components: + - name: testing-dryrun + type: webservice + properties: + image: oamdev/hello-world:v1 + workflow: + steps: + - name: suspend + type: suspend + diff --git a/pkg/appfile/dryrun/testdata/testing-dry-run-4.yaml b/pkg/appfile/dryrun/testdata/testing-dry-run-4.yaml new file mode 100644 index 00000000000..08aec1d4e99 --- /dev/null +++ b/pkg/appfile/dryrun/testdata/testing-dry-run-4.yaml @@ -0,0 +1,16 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: testing-app +spec: + components: + - name: testing-dryrun + type: webservice + properties: + image: oamdev/hello-world:v1 + policies: + - name: mypolicy + type: mypolicy + properties: + name: "my-policy" + diff --git a/pkg/appfile/dryrun/testdata/testing-dry-run-5.yaml b/pkg/appfile/dryrun/testdata/testing-dry-run-5.yaml new file mode 100644 index 00000000000..40e14f16494 --- /dev/null +++ b/pkg/appfile/dryrun/testdata/testing-dry-run-5.yaml @@ -0,0 +1,48 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: testing-app +spec: + components: + - name: testing-dryrun + type: webservice + properties: + image: oamdev/hello-world:v1 + traits: + - type: nocalhost + properties: + port: 9080 + gitUrl: https://github.com/nocalhost/bookinfo-productpage.git + image: nocalhost-docker.pkg.coding.net/nocalhost/dev-images/python:3.7.7-slim-productpage-with-pydevd + shell: "bash" + workDir: "/opt/work" + resources: + limits: + memory: 1Gi + cpu: "1" + requests: + memory: 512Mi + cpu: "0.5" + debug: + remoteDebugPort: 9009 + hotReload: true + sync: + type: send + filePattern: + - ./ + ignoreFilePattern: + - .git + - .idea + command: + run: + - sh + - run.sh + debug: + - sh + - debug.sh + env: + - name: "foo" + value: "bar" + portForward: + - 39080:9080 + diff --git a/references/cli/dryrun.go b/references/cli/dryrun.go index be4b1abe044..da8c66f0ab0 100644 --- a/references/cli/dryrun.go +++ b/references/cli/dryrun.go @@ -20,10 +20,17 @@ import ( "bytes" "context" "encoding/json" + "fmt" "os" "path/filepath" "strings" + wfv1alpha1 "github.com/kubevela/workflow/api/v1alpha1" + "k8s.io/client-go/kubernetes/scheme" + + "github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1" + "github.com/oam-dev/kubevela/pkg/workflow/step" + "github.com/pkg/errors" "github.com/spf13/cobra" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -45,9 +52,10 @@ import ( // DryRunCmdOptions contains dry-run cmd options type DryRunCmdOptions struct { cmdutil.IOStreams - ApplicationFile string - DefinitionFile string - OfflineMode bool + ApplicationFiles []string + DefinitionFile string + OfflineMode bool + MergeStandaloneFiles bool } // NewDryRunCommand creates `dry-run` command @@ -62,8 +70,26 @@ func NewDryRunCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Command You can also specify a remote url for app: vela dry-run -d /definition/directory/or/file/ -f https://remote-host/app.yaml + +And more, you can specify policy and workflow with application file: + vela dry-run -d /definition/directory/or/file/ -f /path/to/app.yaml -f /path/to/policy.yaml -f /path/to/workflow.yaml, OR + vela dry-run -d /definition/directory/or/file/ -f /path/to/app.yaml,/path/to/policy.yaml,/path/to/workflow.yaml + +Additionally, if the provided policy and workflow files are not referenced by application file, warning message will show up +and those files will be ignored. You can use "merge" flag to make those standalone files effective: + vela dry-run -d /definition/directory/or/file/ -f /path/to/app.yaml,/path/to/policy.yaml,/path/to/workflow.yaml --merge + +Limitation: + 1. Only support one object per file(yaml) for "-f" flag. More support will be added in the future improvement. + 2. Dry Run with policy and workflow will only take override/topology policies and deploy workflow step into considerations. Other workflow step will be ignored. +`, + Example: ` +# dry-run application +vela dry-run -f app.yaml + +# dry-run application with policy and workflow +vela dry-run -f app.yaml -f policy.yaml -f workflow.yaml `, - Example: "vela dry-run", Annotations: map[string]string{ types.TagCommandType: types.TypeApp, }, @@ -88,9 +114,10 @@ You can also specify a remote url for app: }, } - cmd.Flags().StringVarP(&o.ApplicationFile, "file", "f", "./app.yaml", "application file name") + cmd.Flags().StringSliceVarP(&o.ApplicationFiles, "file", "f", []string{"app.yaml"}, "application related file names") cmd.Flags().StringVarP(&o.DefinitionFile, "definition", "d", "", "specify a definition file or directory, it will only be used in dry-run rather than applied to K8s cluster") cmd.Flags().BoolVar(&o.OfflineMode, "offline", false, "Run `dry-run` in offline / local mode, all validation steps will be skipped") + cmd.Flags().BoolVar(&o.MergeStandaloneFiles, "merge", false, "Merge standalone files to produce dry-run results") addNamespaceAndEnvArg(cmd) cmd.SetOut(ioStreams.Out) return cmd @@ -140,23 +167,21 @@ func DryRunApplication(cmdOption *DryRunCmdOptions, c common.Args, namespace str // Perform validation only if not in offline mode if !cmdOption.OfflineMode { - err = dryRunOpt.ValidateApp(ctx, cmdOption.ApplicationFile) - if err != nil { - return buff, errors.WithMessagef(err, "validate application: %s by dry-run", cmdOption.ApplicationFile) + for _, applicationFile := range cmdOption.ApplicationFiles { + err = dryRunOpt.ValidateApp(ctx, applicationFile) + if err != nil { + return buff, errors.WithMessagef(err, "validate application: %s by dry-run", applicationFile) + } } } - app, err := readApplicationFromFile(cmdOption.ApplicationFile) + app, err := readApplicationFromFiles(cmdOption, &buff) if err != nil { - return buff, errors.WithMessagef(err, "read application file: %s", cmdOption.ApplicationFile) + return buff, errors.WithMessagef(err, "read application files: %s", cmdOption.ApplicationFiles) } - comps, policies, err := dryRunOpt.ExecuteDryRun(ctx, app) + err = dryRunOpt.ExecuteDryRunWithPolicies(ctx, app, &buff) if err != nil { - return buff, errors.WithMessage(err, "generate OAM objects") - } - - if err = dryRunOpt.PrintDryRun(&buff, app.Name, comps, policies); err != nil { return buff, err } return buff, nil @@ -241,3 +266,140 @@ func readApplicationFromFile(filename string) (*corev1beta1.Application, error) err = json.Unmarshal(fileContent, app) return app, err } + +func readApplicationFromFiles(cmdOption *DryRunCmdOptions, buff *bytes.Buffer) (*corev1beta1.Application, error) { + var app *corev1beta1.Application + var policies []*v1alpha1.Policy + var wf *wfv1alpha1.Workflow + policyNameMap := make(map[string]struct{}) + + for _, filename := range cmdOption.ApplicationFiles { + fileContent, err := utils.ReadRemoteOrLocalPath(filename, true) + if err != nil { + return nil, err + } + + fileType := filepath.Ext(filename) + switch fileType { + case ".yaml", ".yml": + // only support one object in one yaml file + fileContent, err = yaml.YAMLToJSON(fileContent) + if err != nil { + return nil, err + } + decode := scheme.Codecs.UniversalDeserializer().Decode + // cannot guarantee get the object, but gkv is enough + _, gkv, _ := decode(fileContent, nil, nil) + + jsonFileContent, err := yaml.YAMLToJSON(fileContent) + if err != nil { + return nil, err + } + + switch *gkv { + case corev1beta1.ApplicationKindVersionKind: + if app != nil { + return nil, errors.New("more than one applications provided") + } + app = new(corev1beta1.Application) + err = json.Unmarshal(jsonFileContent, app) + if err != nil { + return nil, err + } + case v1alpha1.PolicyGroupVersionKind: + policy := new(v1alpha1.Policy) + err = json.Unmarshal(jsonFileContent, policy) + if err != nil { + return nil, err + } + policies = append(policies, policy) + case v1alpha1.WorkflowGroupVersionKind: + if wf != nil { + return nil, errors.New("more than one external workflow provided") + } + wf = new(wfv1alpha1.Workflow) + err = json.Unmarshal(jsonFileContent, wf) + if err != nil { + return nil, err + } + default: + return nil, fmt.Errorf("file %s is not application, policy or workflow", filename) + } + } + } + + // only allow one application + if app == nil { + return nil, errors.New("no application provided") + } + + // workflow not referenced by application + if !cmdOption.MergeStandaloneFiles { + if wf != nil && + ((app.Spec.Workflow != nil && app.Spec.Workflow.Ref != wf.Name) || app.Spec.Workflow == nil) { + buff.WriteString(fmt.Sprintf("WARNING: workflow %s not referenced by application\n\n", wf.Name)) + } + } else { + if wf != nil { + app.Spec.Workflow = &corev1beta1.Workflow{ + Ref: "", + Steps: wf.Steps, + } + } + err := getPolicyNameFromWorkflow(wf, policyNameMap) + if err != nil { + return nil, err + } + } + + for _, policy := range policies { + // check standalone policies + if _, exist := policyNameMap[policy.Name]; !exist && !cmdOption.MergeStandaloneFiles { + buff.WriteString(fmt.Sprintf("WARNING: policy %s not referenced by application\n\n", policy.Name)) + continue + } + app.Spec.Policies = append(app.Spec.Policies, corev1beta1.AppPolicy{ + Name: policy.Name, + Type: policy.Type, + Properties: policy.Properties, + }) + } + return app, nil +} + +func getPolicyNameFromWorkflow(wf *wfv1alpha1.Workflow, policyNameMap map[string]struct{}) error { + + checkPolicy := func(wfsb wfv1alpha1.WorkflowStepBase, policyNameMap map[string]struct{}) error { + workflowStepSpec := &step.DeployWorkflowStepSpec{} + if err := utils.StrictUnmarshal(wfsb.Properties.Raw, workflowStepSpec); err != nil { + return err + } + for _, p := range workflowStepSpec.Policies { + policyNameMap[p] = struct{}{} + } + return nil + } + + if wf == nil { + return nil + } + + for _, wfs := range wf.Steps { + if wfs.Type == step.DeployWorkflowStep { + err := checkPolicy(wfs.WorkflowStepBase, policyNameMap) + if err != nil { + return err + } + for _, sub := range wfs.SubSteps { + if sub.Type == step.DeployWorkflowStep { + err = checkPolicy(sub, policyNameMap) + if err != nil { + return err + } + } + } + + } + } + return nil +} diff --git a/references/cli/dryrun_test.go b/references/cli/dryrun_test.go index c9c79b48235..d5204d7cf6d 100644 --- a/references/cli/dryrun_test.go +++ b/references/cli/dryrun_test.go @@ -17,24 +17,27 @@ package cli import ( - "bytes" "context" "os" "strings" + wfv1alpha1 "github.com/kubevela/workflow/api/v1alpha1" + + "github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "sigs.k8s.io/yaml" "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" - "github.com/oam-dev/kubevela/pkg/oam/discoverymapper" common2 "github.com/oam-dev/kubevela/pkg/utils/common" ) -var _ = Describe("Test dry run with policy", func() { - It("Test dry run with normal policy", func() { +var _ = Describe("Testing dry-run", func() { + + It("Testing dry-run", func() { + webservice, err := os.ReadFile("../../charts/vela-core/templates/defwithtemplate/webservice.yaml") Expect(err).Should(BeNil()) webserviceYAML := strings.Replace(string(webservice), "{{ include \"systemDefinitionNamespace\" . }}", types.DefaultKubeVelaNS, 1) @@ -42,100 +45,195 @@ var _ = Describe("Test dry run with policy", func() { Expect(yaml.Unmarshal([]byte(webserviceYAML), &wwd)).Should(BeNil()) Expect(k8sClient.Create(context.TODO(), &wwd)).Should(BeNil()) - plcd := v1beta1.PolicyDefinition{} - Expect(yaml.Unmarshal([]byte(plcdef), &plcd)).Should(BeNil()) - plcd.Namespace = types.DefaultKubeVelaNS - Expect(k8sClient.Create(context.TODO(), &plcd)).Should(BeNil()) - app := v1beta1.Application{} - Expect(yaml.Unmarshal([]byte(plcapp), &app)).Should(BeNil()) + scaler, err := os.ReadFile("../../charts/vela-core/templates/defwithtemplate/scaler.yaml") + Expect(err).Should(BeNil()) + scalerYAML := strings.Replace(string(scaler), "{{ include \"systemDefinitionNamespace\" . }}", types.DefaultKubeVelaNS, 1) + var td v1beta1.TraitDefinition + Expect(yaml.Unmarshal([]byte(scalerYAML), &td)).Should(BeNil()) + Expect(k8sClient.Create(context.TODO(), &td)).Should(BeNil()) + c := common2.Args{} c.SetConfig(cfg) c.SetClient(k8sClient) - pd, err := c.GetPackageDiscover() + opt := DryRunCmdOptions{ApplicationFiles: []string{"test-data/dry-run/testing-dry-run-1.yaml"}, OfflineMode: false} + buff, err := DryRunApplication(&opt, c, "") Expect(err).Should(BeNil()) - dm, err := discoverymapper.New(cfg) + Expect(buff.String()).Should(ContainSubstring("name: testing-dryrun")) + Expect(buff.String()).Should(ContainSubstring("kind: Deployment")) + Expect(buff.String()).Should(ContainSubstring("replicas: 1")) + }) + + It("Testing dry-run with policy", func() { + deploy, err := os.ReadFile("../../charts/vela-core/templates/defwithtemplate/deploy.yaml") + Expect(err).Should(BeNil()) + deployYAML := strings.Replace(string(deploy), "{{ include \"systemDefinitionNamespace\" . }}", types.DefaultKubeVelaNS, 1) + var wfsd v1beta1.WorkflowStepDefinition + Expect(yaml.Unmarshal([]byte(deployYAML), &wfsd)).Should(BeNil()) + Expect(k8sClient.Create(context.TODO(), &wfsd)).Should(BeNil()) + + c := common2.Args{} + c.SetConfig(cfg) + c.SetClient(k8sClient) + opt := DryRunCmdOptions{ApplicationFiles: []string{"test-data/dry-run/testing-dry-run-2.yaml"}, OfflineMode: false} + buff, err := DryRunApplication(&opt, c, "") + Expect(err).Should(BeNil()) + Expect(buff.String()).Should(ContainSubstring("# Application(testing-app with topology target-default)")) + Expect(buff.String()).Should(ContainSubstring("name: testing-dryrun")) + Expect(buff.String()).Should(ContainSubstring("kind: Deployment")) + Expect(buff.String()).Should(ContainSubstring("replicas: 1")) + }) + + It("Testing dry-run with workflow", func() { + + c := common2.Args{} + c.SetConfig(cfg) + c.SetClient(k8sClient) + opt := DryRunCmdOptions{ApplicationFiles: []string{"test-data/dry-run/testing-dry-run-3.yaml"}, OfflineMode: false} + buff, err := DryRunApplication(&opt, c, "") + Expect(err).Should(BeNil()) + Expect(buff.String()).Should(ContainSubstring("# Application(testing-app with topology target-default)")) + Expect(buff.String()).Should(ContainSubstring("# Application(testing-app with topology target-prod)")) + Expect(buff.String()).Should(ContainSubstring("name: testing-dryrun")) + Expect(buff.String()).Should(ContainSubstring("kind: Deployment")) + Expect(buff.String()).Should(ContainSubstring("replicas: 1")) + Expect(buff.String()).Should(ContainSubstring("replicas: 3")) + }) + + It("Testing dry-run with ref workflow", func() { + + policy, err := os.ReadFile("test-data/dry-run/testing-policy.yaml") + Expect(err).Should(BeNil()) + var p v1alpha1.Policy + Expect(yaml.Unmarshal([]byte(policy), &p)).Should(BeNil()) + Expect(k8sClient.Create(context.TODO(), &p)).Should(BeNil()) + + workflow, err := os.ReadFile("test-data/dry-run/testing-wf.yaml") + Expect(err).Should(BeNil()) + var wf wfv1alpha1.Workflow + Expect(yaml.Unmarshal([]byte(workflow), &wf)).Should(BeNil()) + Expect(k8sClient.Create(context.TODO(), &wf)).Should(BeNil()) + + c := common2.Args{} + c.SetConfig(cfg) + c.SetClient(k8sClient) + opt := DryRunCmdOptions{ApplicationFiles: []string{"test-data/dry-run/testing-dry-run-4.yaml"}, OfflineMode: false} + buff, err := DryRunApplication(&opt, c, "") + Expect(err).Should(BeNil()) + Expect(buff.String()).Should(ContainSubstring("# Application(testing-app with topology deploy-somewhere)")) + Expect(buff.String()).Should(ContainSubstring("name: testing-dryrun")) + Expect(buff.String()).Should(ContainSubstring("kind: Deployment")) + }) + + It("Testing dry-run without application provided", func() { + + c := common2.Args{} + c.SetConfig(cfg) + c.SetClient(k8sClient) + opt := DryRunCmdOptions{ApplicationFiles: []string{"test-data/dry-run/testing-policy.yaml"}, OfflineMode: false} + _, err := DryRunApplication(&opt, c, "") + Expect(err).ShouldNot(BeNil()) + Expect(err.Error()).Should(ContainSubstring("no application provided")) + + }) + + It("Testing dry-run with more than one applications provided", func() { + + c := common2.Args{} + c.SetConfig(cfg) + c.SetClient(k8sClient) + opt := DryRunCmdOptions{ApplicationFiles: []string{"test-data/dry-run/testing-dry-run-1.yaml", "test-data/dry-run/testing-dry-run-2.yaml"}, OfflineMode: false} + _, err := DryRunApplication(&opt, c, "") + Expect(err).ShouldNot(BeNil()) + Expect(err.Error()).Should(ContainSubstring("more than one applications provided")) + + }) + + It("Testing dry-run with more than one workflow provided", func() { + + c := common2.Args{} + c.SetConfig(cfg) + c.SetClient(k8sClient) + opt := DryRunCmdOptions{ApplicationFiles: []string{"test-data/dry-run/testing-dry-run-1.yaml", "test-data/dry-run/testing-wf.yaml", "test-data/dry-run/testing-wf.yaml"}, OfflineMode: false} + _, err := DryRunApplication(&opt, c, "") + Expect(err).ShouldNot(BeNil()) + Expect(err.Error()).Should(ContainSubstring("more than one external workflow provided")) + + }) + + It("Testing dry-run with unexpected file", func() { + + c := common2.Args{} + c.SetConfig(cfg) + c.SetClient(k8sClient) + opt := DryRunCmdOptions{ApplicationFiles: []string{"test-data/dry-run/testing-trait.yaml"}, OfflineMode: false} + _, err := DryRunApplication(&opt, c, "") + Expect(err).ShouldNot(BeNil()) + Expect(err.Error()).Should(ContainSubstring("is not application, policy or workflow")) + + }) + + It("Testing dry-run with unexpected file", func() { + + c := common2.Args{} + c.SetConfig(cfg) + c.SetClient(k8sClient) + opt := DryRunCmdOptions{ApplicationFiles: []string{"test-data/dry-run/testing-trait.yaml"}, OfflineMode: false} + _, err := DryRunApplication(&opt, c, "") + Expect(err).ShouldNot(BeNil()) + Expect(err.Error()).Should(ContainSubstring("is not application, policy or workflow")) + + }) + + It("Testing dry-run merging with external workflow and policy", func() { + + c := common2.Args{} + c.SetConfig(cfg) + c.SetClient(k8sClient) + opt := DryRunCmdOptions{ApplicationFiles: []string{"test-data/dry-run/testing-dry-run-5.yaml", "test-data/dry-run/testing-wf.yaml", "test-data/dry-run/testing-policy.yaml"}, OfflineMode: false, MergeStandaloneFiles: true} + buff, err := DryRunApplication(&opt, c, "") Expect(err).Should(BeNil()) + Expect(buff.String()).Should(ContainSubstring("# Application(testing-app with topology deploy-somewhere)")) + Expect(buff.String()).Should(ContainSubstring("name: testing-dryrun")) + Expect(buff.String()).Should(ContainSubstring("kind: Deployment")) + }) - dryRunOpt := dryrun.NewDryRunOption(k8sClient, cfg, dm, pd, nil, false) + It("Testing dry-run with standalone policy", func() { - comps, plcs, err := dryRunOpt.ExecuteDryRun(context.TODO(), &app) + c := common2.Args{} + c.SetConfig(cfg) + c.SetClient(k8sClient) + opt := DryRunCmdOptions{ApplicationFiles: []string{"test-data/dry-run/testing-dry-run-5.yaml", "test-data/dry-run/testing-policy.yaml"}, OfflineMode: false, MergeStandaloneFiles: false} + buff, err := DryRunApplication(&opt, c, "") Expect(err).Should(BeNil()) - speci := plcs[0].Object["spec"].(map[string]interface{}) - Expect(speci["service"].(string)).Should(BeEquivalentTo("unified")) - buff := bytes.NewBufferString("") - Expect(dryRunOpt.PrintDryRun(buff, app.Name, comps, plcs)).Should(BeNil()) - Expect(buff.String()).Should(ContainSubstring(`backends: - - service: server-v1 - weight: 80 - - service: server-v2 - weight: 20 - service: unified`)) - Expect(buff.String()).Should(ContainSubstring("- image: oamdev/hello-world:v1\n name: server-v1")) - Expect(buff.String()).Should(ContainSubstring("- image: oamdev/hello-world:v2\n name: server-v2")) + Expect(buff.String()).Should(ContainSubstring("WARNING: policy deploy-somewhere not referenced by application")) + Expect(buff.String()).Should(ContainSubstring("name: testing-dryrun")) + Expect(buff.String()).Should(ContainSubstring("kind: Deployment")) }) - It("Test dry run with cue component format", func() { + It("Testing dry-run with standalone workflow", func() { c := common2.Args{} c.SetConfig(cfg) c.SetClient(k8sClient) + opt := DryRunCmdOptions{ApplicationFiles: []string{"test-data/dry-run/testing-dry-run-5.yaml", "test-data/dry-run/testing-wf.yaml"}, OfflineMode: false, MergeStandaloneFiles: false} + buff, err := DryRunApplication(&opt, c, "") + Expect(err).Should(BeNil()) + Expect(buff.String()).Should(ContainSubstring("WARNING: workflow testing-wf not referenced by application")) + Expect(buff.String()).Should(ContainSubstring("name: testing-dryrun")) + Expect(buff.String()).Should(ContainSubstring("kind: Deployment")) + }) + + It("Testing dry-run offline", func() { - opt := DryRunCmdOptions{ApplicationFile: "test-data/dry-run/app.yaml", DefinitionFile: "test-data/dry-run/my-comp.cue", OfflineMode: true} + c := common2.Args{} + c.SetConfig(cfg) + c.SetClient(k8sClient) + opt := DryRunCmdOptions{ApplicationFiles: []string{"test-data/dry-run/testing-dry-run-6.yaml"}, DefinitionFile: "test-data/dry-run/testing-worker-def.yaml", OfflineMode: true} buff, err := DryRunApplication(&opt, c, "") Expect(err).Should(BeNil()) - Expect(buff.String()).Should(ContainSubstring("name: hello-world")) + Expect(buff.String()).Should(ContainSubstring("# Application(testing-app)")) + Expect(buff.String()).Should(ContainSubstring("name: testing-dryrun")) Expect(buff.String()).Should(ContainSubstring("kind: Deployment")) - Expect(buff.String()).Should(ContainSubstring("name: hello-world-service")) - Expect(buff.String()).Should(ContainSubstring("kind: Service")) + Expect(buff.String()).Should(ContainSubstring("workload.oam.dev/type: myworker")) }) }) - -var plcapp = `apiVersion: core.oam.dev/v1beta1 -kind: Application -metadata: - name: my-test-2 -spec: - components: - - name: server-v1 - type: webservice - properties: - image: oamdev/hello-world:v1 - - name: server-v2 - type: webservice - properties: - image: oamdev/hello-world:v2 - policies: - - type: my-plc - name: unified - properties: - weights: - - service: server-v1 - weight: 80 - - service: server-v2 - weight: 20 -` - -var plcdef = `apiVersion: core.oam.dev/v1beta1 -kind: PolicyDefinition -metadata: - annotations: - definition.oam.dev/description: My ingress route policy. - name: my-plc -spec: - schematic: - cue: - template: | - #ServerWeight: { - service: string - weight: int - } - parameter: weights: [...#ServerWeight] - output: { - apiVersion: "split.smi-spec.io/v1alpha3" - kind: "TrafficSplit" - metadata: name: context.name - spec: { - service: context.name - backends: parameter.weights - } - }` diff --git a/references/cli/livediff.go b/references/cli/livediff.go index c0aa4920180..93944d016da 100644 --- a/references/cli/livediff.go +++ b/references/cli/livediff.go @@ -37,7 +37,9 @@ import ( // LiveDiffCmdOptions contains the live-diff cmd options type LiveDiffCmdOptions struct { - DryRunCmdOptions + cmdutil.IOStreams + ApplicationFile string + DefinitionFile string AppName string Namespace string Revision string @@ -47,10 +49,8 @@ type LiveDiffCmdOptions struct { // NewLiveDiffCommand creates `live-diff` command func NewLiveDiffCommand(c common.Args, order string, ioStreams cmdutil.IOStreams) *cobra.Command { - o := &LiveDiffCmdOptions{ - DryRunCmdOptions: DryRunCmdOptions{ - IOStreams: ioStreams, - }} + o := &LiveDiffCmdOptions{IOStreams: ioStreams} + cmd := &cobra.Command{ Use: "live-diff", DisableFlagsInUseLine: true, diff --git a/references/cli/test-data/dry-run/app.yaml b/references/cli/test-data/dry-run/app.yaml deleted file mode 100644 index ceb91dde3d1..00000000000 --- a/references/cli/test-data/dry-run/app.yaml +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 8a9a985672a..00000000000 --- a/references/cli/test-data/dry-run/my-comp.cue +++ /dev/null @@ -1,50 +0,0 @@ -"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: {} - -} diff --git a/references/cli/test-data/dry-run/testing-dry-run-1.yaml b/references/cli/test-data/dry-run/testing-dry-run-1.yaml new file mode 100644 index 00000000000..74b393f412f --- /dev/null +++ b/references/cli/test-data/dry-run/testing-dry-run-1.yaml @@ -0,0 +1,16 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: testing-app +spec: + components: + - name: testing-dryrun + type: webservice + properties: + image: oamdev/hello-world:v1 + traits: + - type: scaler + properties: + replicas: 1 + + diff --git a/references/cli/test-data/dry-run/testing-dry-run-2.yaml b/references/cli/test-data/dry-run/testing-dry-run-2.yaml new file mode 100644 index 00000000000..7eff65d8459 --- /dev/null +++ b/references/cli/test-data/dry-run/testing-dry-run-2.yaml @@ -0,0 +1,20 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: testing-app +spec: + components: + - name: testing-dryrun + type: webservice + properties: + image: oamdev/hello-world:v1 + traits: + - type: scaler + properties: + replicas: 1 + policies: + - name: target-default + type: topology + properties: + clusters: [ "local" ] + namespace: "default" \ No newline at end of file diff --git a/references/cli/test-data/dry-run/testing-dry-run-3.yaml b/references/cli/test-data/dry-run/testing-dry-run-3.yaml new file mode 100644 index 00000000000..3f152f01737 --- /dev/null +++ b/references/cli/test-data/dry-run/testing-dry-run-3.yaml @@ -0,0 +1,44 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: testing-app +spec: + components: + - name: testing-dryrun + type: webservice + properties: + image: oamdev/hello-world:v1 + traits: + - type: scaler + properties: + replicas: 1 + policies: + - name: target-default + type: topology + properties: + clusters: [ "local" ] + namespace: "default" + - name: target-prod + type: topology + properties: + clusters: [ "local" ] + namespace: "prod" + - name: deploy-ha + type: override + properties: + components: + - type: webservice + traits: + - type: scaler + properties: + replicas: 3 + workflow: + steps: + - name: deploy2default + type: deploy + properties: + policies: [ "target-default" ] + - name: deploy2prod + type: deploy + properties: + policies: [ "target-prod", "deploy-ha" ] \ No newline at end of file diff --git a/references/cli/test-data/dry-run/testing-dry-run-4.yaml b/references/cli/test-data/dry-run/testing-dry-run-4.yaml new file mode 100644 index 00000000000..27fb563499d --- /dev/null +++ b/references/cli/test-data/dry-run/testing-dry-run-4.yaml @@ -0,0 +1,12 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: testing-app +spec: + components: + - name: testing-dryrun + type: webservice + properties: + image: oamdev/hello-world:v1 + workflow: + ref: testing-wf diff --git a/references/cli/test-data/dry-run/testing-dry-run-5.yaml b/references/cli/test-data/dry-run/testing-dry-run-5.yaml new file mode 100644 index 00000000000..513c16879fb --- /dev/null +++ b/references/cli/test-data/dry-run/testing-dry-run-5.yaml @@ -0,0 +1,11 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: testing-app +spec: + components: + - name: testing-dryrun + type: webservice + properties: + image: oamdev/hello-world:v1 + diff --git a/references/cli/test-data/dry-run/testing-dry-run-6.yaml b/references/cli/test-data/dry-run/testing-dry-run-6.yaml new file mode 100644 index 00000000000..66e6b130d21 --- /dev/null +++ b/references/cli/test-data/dry-run/testing-dry-run-6.yaml @@ -0,0 +1,12 @@ +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: testing-app +spec: + components: + - name: testing-dryrun + type: myworker + properties: + image: oamdev/hello-world:v1 + + diff --git a/references/cli/test-data/dry-run/testing-policy.yaml b/references/cli/test-data/dry-run/testing-policy.yaml new file mode 100644 index 00000000000..4a2d13e6734 --- /dev/null +++ b/references/cli/test-data/dry-run/testing-policy.yaml @@ -0,0 +1,8 @@ +apiVersion: core.oam.dev/v1alpha1 +kind: Policy +metadata: + name: deploy-somewhere + namespace: default +type: topology +properties: + clusters: ["anywhere"] \ No newline at end of file diff --git a/references/cli/test-data/dry-run/testing-trait.yaml b/references/cli/test-data/dry-run/testing-trait.yaml new file mode 100644 index 00000000000..a056db6ae38 --- /dev/null +++ b/references/cli/test-data/dry-run/testing-trait.yaml @@ -0,0 +1,8 @@ +apiVersion: core.oam.dev/v1alpha2 +kind: TraitDefinition +metadata: + name: bars.example.com + namespace: default +spec: + definitionRef: + name: bars.example.com \ No newline at end of file diff --git a/references/cli/test-data/dry-run/testing-wf.yaml b/references/cli/test-data/dry-run/testing-wf.yaml new file mode 100644 index 00000000000..c11c6dd8ea7 --- /dev/null +++ b/references/cli/test-data/dry-run/testing-wf.yaml @@ -0,0 +1,10 @@ +apiVersion: core.oam.dev/v1alpha1 +kind: Workflow +metadata: + name: testing-wf + namespace: default +steps: + - type: deploy + name: deploy-somewhere + properties: + policies: ["deploy-somewhere"] \ No newline at end of file diff --git a/references/cli/test-data/dry-run/testing-worker-def.yaml b/references/cli/test-data/dry-run/testing-worker-def.yaml new file mode 100644 index 00000000000..57ce4ae470f --- /dev/null +++ b/references/cli/test-data/dry-run/testing-worker-def.yaml @@ -0,0 +1,49 @@ +apiVersion: core.oam.dev/v1beta1 +kind: ComponentDefinition +metadata: + name: myworker +spec: + workload: + definition: + apiVersion: apps/v1 + kind: Deployment + schematic: + cue: + template: | + output: { + apiVersion: "apps/v1" + kind: "Deployment" + } + output: { + spec: { + selector: matchLabels: { + "app.oam.dev/component": context.name + } + + template: { + metadata: labels: { + "app.oam.dev/component": context.name + } + + spec: { + containers: [{ + name: context.name + image: parameter.image + + if parameter["cmd"] != _|_ { + command: parameter.cmd + } + }] + } + } + } + } + + parameter: { + // +usage=Which image would you like to use for your service + // +short=i + image: string + // +usage=Commands to run in the container + cmd?: [...string] + } +