diff --git a/pkg/appfile/dryrun/diff.go b/pkg/appfile/dryrun/diff.go index 1faebd189..cab39e8f1 100644 --- a/pkg/appfile/dryrun/diff.go +++ b/pkg/appfile/dryrun/diff.go @@ -146,9 +146,19 @@ func (l *LiveDiffOption) RenderlessDiff(ctx context.Context, base, comparor Live } if af.ExternalWorkflow != nil { if bs, err = marshalObject(af.ExternalWorkflow); err == nil { - m.Subs = append(m.Subs, &manifest{Name: af.Name, Kind: WorkflowKind, Data: string(bs)}) + m.Subs = append(m.Subs, &manifest{Name: af.ExternalWorkflow.Name, Kind: WorkflowKind, Data: string(bs)}) } else { - m.Subs = append(m.Subs, &manifest{Name: af.Name, Kind: WorkflowKind, Data: "Error: " + errors.Wrapf(err, "failed to marshal external workflow %s", af.ExternalWorkflow.Name).Error()}) + m.Subs = append(m.Subs, &manifest{Name: af.ExternalWorkflow.Name, Kind: WorkflowKind, Data: "Error: " + errors.Wrapf(err, "failed to marshal external workflow %s", af.ExternalWorkflow.Name).Error()}) + } + } + if af.ReferredObjects != nil { + for _, refObj := range af.ReferredObjects { + manifestName := fmt.Sprintf("%s %s %s", refObj.GetAPIVersion(), refObj.GetKind(), client.ObjectKeyFromObject(refObj).String()) + if bs, err = marshalObject(refObj); err == nil { + m.Subs = append(m.Subs, &manifest{Name: manifestName, Kind: ReferredObject, Data: string(bs)}) + } else { + m.Subs = append(m.Subs, &manifest{Name: manifestName, Kind: ReferredObject, Data: "Error: " + errors.Wrapf(err, "failed to marshal referred object").Error()}) + } } } return m, nil diff --git a/pkg/appfile/dryrun/diff_test.go b/pkg/appfile/dryrun/diff_test.go index b71d0fdb4..4ace15d8e 100644 --- a/pkg/appfile/dryrun/diff_test.go +++ b/pkg/appfile/dryrun/diff_test.go @@ -197,20 +197,27 @@ var _ = Describe("Test Live-Diff", func() { applyFile("td-myscaler.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") Expect(runDiff()).Should(ContainSubstring("topology-local not found")) applyFile("external-policy.yaml", "default") + Expect(runDiff()).Should(ContainSubstring("deployments.apps \"livediff-demo\" not found")) + applyFile("livediff-demo-deploy.yaml", "default") + e := runDiff() + _ = e Expect(runDiff()).Should(SatisfyAll( ContainSubstring("Application (livediff-demo) has been modified(*)"), ContainSubstring("External Policy (topology-local) has been added(+)"), - ContainSubstring("External Workflow (livediff-demo) has been added(+)"), + ContainSubstring("External Workflow (deploy-livediff-demo) has been added(+)"), + ContainSubstring("Referred Object (apps/v1 Deployment default/livediff-demo) has been added(+)"), )) reverse = true Expect(runDiff()).Should(SatisfyAll( ContainSubstring("Application (livediff-demo) has been modified(*)"), ContainSubstring("External Policy (topology-local) has been removed(-)"), - ContainSubstring("External Workflow (livediff-demo) has been removed(-)"), + ContainSubstring("External Workflow (deploy-livediff-demo) has been removed(-)"), + ContainSubstring("Referred Object (apps/v1 Deployment default/livediff-demo) has been removed(-)"), )) }) diff --git a/pkg/appfile/dryrun/testdata/diff-input-app-with-externals.yaml b/pkg/appfile/dryrun/testdata/diff-input-app-with-externals.yaml index 2f8361a89..cc8fd40fa 100644 --- a/pkg/appfile/dryrun/testdata/diff-input-app-with-externals.yaml +++ b/pkg/appfile/dryrun/testdata/diff-input-app-with-externals.yaml @@ -23,14 +23,10 @@ spec: - type: myscaler properties: replicas: 2 - - name: myweb-3 - type: myworker + - name: livediff-demo + type: ref-objects properties: - image: "busybox" - cmd: - - sleep - - "1000" - lives: "3" - enemies: "alien" + objects: + - resource: deployment workflow: ref: deploy-livediff-demo \ No newline at end of file diff --git a/pkg/appfile/dryrun/testdata/livediff-demo-deploy.yaml b/pkg/appfile/dryrun/testdata/livediff-demo-deploy.yaml new file mode 100644 index 000000000..c1fd1a70d --- /dev/null +++ b/pkg/appfile/dryrun/testdata/livediff-demo-deploy.yaml @@ -0,0 +1,17 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: livediff-demo +spec: + replicas: 0 + selector: + matchLabels: + app: livediff-demo + template: + metadata: + labels: + app: livediff-demo + spec: + containers: + - image: busybox + name: livediff-demo \ No newline at end of file diff --git a/pkg/appfile/dryrun/testdata/wd-ref-objects.yaml b/pkg/appfile/dryrun/testdata/wd-ref-objects.yaml new file mode 100644 index 000000000..ef6fd7789 --- /dev/null +++ b/pkg/appfile/dryrun/testdata/wd-ref-objects.yaml @@ -0,0 +1,31 @@ +apiVersion: core.oam.dev/v1beta1 +kind: ComponentDefinition +metadata: + annotations: + definition.oam.dev/description: Ref-objects allow users to specify ref objects to use. Notice that this component type have special handle logic. + name: ref-objects +spec: + schematic: + cue: + template: | + #K8sObject: { + apiVersion: string + kind: string + metadata: { + name: string + ... + } + ... + } + output: parameter.objects[0] + outputs: { + for i, v in parameter.objects { + if i > 0 { + "objects-\(i)": v + } + } + } + parameter: objects: [...#K8sObject] + workload: + type: autodetects.core.oam.dev + diff --git a/pkg/appfile/parser.go b/pkg/appfile/parser.go index 283c27a28..e1923f3b9 100644 --- a/pkg/appfile/parser.go +++ b/pkg/appfile/parser.go @@ -310,7 +310,7 @@ func (p *Parser) parseReferredObjectsFromRevision(af *Appfile) error { func (p *Parser) parseReferredObjects(ctx context.Context, af *Appfile) error { for _, comp := range af.Components { if comp.Type != v1alpha1.RefObjectsComponentType { - return nil + continue } spec := &v1alpha1.RefObjectsComponentSpec{} if err := utils.StrictUnmarshal(comp.Properties.Raw, spec); err != nil { diff --git a/test/e2e-multicluster-test/multicluster_standalone_test.go b/test/e2e-multicluster-test/multicluster_standalone_test.go index 322debb04..ab3b0e539 100644 --- a/test/e2e-multicluster-test/multicluster_standalone_test.go +++ b/test/e2e-multicluster-test/multicluster_standalone_test.go @@ -186,7 +186,8 @@ var _ = Describe("Test multicluster standalone scenario", func() { By("Apply application successfully") applyFile("topology-policy.yaml") applyFile("workflow-deploy-worker.yaml") - applyFile("app-with-publish-version-native.yaml") + applyFile("deployment-busybox.yaml") + applyFile("app-with-publish-version-busybox.yaml") app := &v1beta1.Application{} appKey := types.NamespacedName{Namespace: namespace, Name: "busybox"} Eventually(func(g Gomega) { @@ -229,20 +230,30 @@ var _ = Describe("Test multicluster standalone scenario", func() { g.Expect(k8sClient.Update(hubCtx, policy)).Should(Succeed()) }, 30*time.Second).Should(Succeed()) + By("Change referred objects") + Eventually(func(g Gomega) { + deploy := &v1.Deployment{} + g.Expect(k8sClient.Get(hubCtx, types.NamespacedName{Namespace: namespace, Name: "busybox-ref"}, deploy)).Should(Succeed()) + deploy.Spec.Replicas = pointer.Int32(1) + g.Expect(k8sClient.Update(hubCtx, deploy)).Should(Succeed()) + }, 30*time.Second).Should(Succeed()) + By("Live-diff application") outputs, err := execCommand("live-diff", "-r", "busybox-v3,busybox-v1", "-n", namespace) Expect(err).Should(Succeed()) Expect(outputs).Should(SatisfyAll( ContainSubstring("Application (busybox) has been modified(*)"), ContainSubstring("External Policy (topology-worker) has no change"), - ContainSubstring("External Workflow (busybox) has no change"), + ContainSubstring("External Workflow (deploy-worker) has no change"), + ContainSubstring(fmt.Sprintf("Referred Object (apps/v1 Deployment %s/busybox-ref) has no change", namespace)), )) outputs, err = execCommand("live-diff", "busybox", "-n", namespace) Expect(err).Should(Succeed()) Expect(outputs).Should(SatisfyAll( ContainSubstring("Application (busybox) has no change"), ContainSubstring("External Policy (topology-worker) has been modified(*)"), - ContainSubstring("External Workflow (busybox) has no change"), + ContainSubstring("External Workflow (deploy-worker) has no change"), + ContainSubstring(fmt.Sprintf("Referred Object (apps/v1 Deployment %s/busybox-ref) has been modified", namespace)), )) By("Rollback application") @@ -257,6 +268,8 @@ var _ = Describe("Test multicluster standalone scenario", func() { deploy := &v1.Deployment{} g.Expect(k8sClient.Get(workerCtx, types.NamespacedName{Namespace: namespace, Name: "busybox"}, deploy)).Should(Succeed()) g.Expect(deploy.Spec.Template.Spec.Containers[0].Image).Should(Equal("busybox")) + g.Expect(k8sClient.Get(workerCtx, types.NamespacedName{Namespace: namespace, Name: "busybox-ref"}, deploy)).Should(Succeed()) + g.Expect(deploy.Spec.Replicas).Should(Equal(pointer.Int32(0))) revs, err := application.GetSortedAppRevisions(hubCtx, k8sClient, app.Name, namespace) g.Expect(err).Should(Succeed()) g.Expect(len(revs)).Should(Equal(1)) diff --git a/test/e2e-multicluster-test/testdata/app/standalone/app-with-publish-version-native.yaml b/test/e2e-multicluster-test/testdata/app/standalone/app-with-publish-version-busybox.yaml similarity index 72% rename from test/e2e-multicluster-test/testdata/app/standalone/app-with-publish-version-native.yaml rename to test/e2e-multicluster-test/testdata/app/standalone/app-with-publish-version-busybox.yaml index 2ab77c6a5..bcdbb9f8b 100644 --- a/test/e2e-multicluster-test/testdata/app/standalone/app-with-publish-version-native.yaml +++ b/test/e2e-multicluster-test/testdata/app/standalone/app-with-publish-version-busybox.yaml @@ -11,5 +11,10 @@ spec: properties: image: busybox cmd: [ "sleep", "86400" ] + - name: busybox-ref + type: ref-objects + properties: + objects: + - resource: deployment workflow: ref: deploy-worker \ No newline at end of file diff --git a/test/e2e-multicluster-test/testdata/app/standalone/deployment-busybox.yaml b/test/e2e-multicluster-test/testdata/app/standalone/deployment-busybox.yaml new file mode 100644 index 000000000..51289237b --- /dev/null +++ b/test/e2e-multicluster-test/testdata/app/standalone/deployment-busybox.yaml @@ -0,0 +1,17 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: busybox-ref +spec: + replicas: 0 + selector: + matchLabels: + app: busybox + template: + metadata: + labels: + app: busybox + spec: + containers: + - image: busybox + name: busybox \ No newline at end of file