diff --git a/go.mod b/go.mod index 9430b5308..db0e4a937 100644 --- a/go.mod +++ b/go.mod @@ -58,7 +58,7 @@ require ( github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c github.com/kubevela/pkg v0.0.0-20221024115939-a103acee6db2 github.com/kubevela/prism v1.5.1-0.20220915071949-6bf3ad33f84f - github.com/kubevela/workflow v0.3.4 + github.com/kubevela/workflow v0.3.5-0.20221115021445-48df288898ad github.com/kyokomi/emoji v2.2.4+incompatible github.com/mitchellh/hashstructure/v2 v2.0.1 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd diff --git a/go.sum b/go.sum index bbfd870b5..d42ab0ad9 100644 --- a/go.sum +++ b/go.sum @@ -1335,8 +1335,8 @@ github.com/kubevela/pkg v0.0.0-20221024115939-a103acee6db2 h1:C3cAfrxst1+dIWgLLh github.com/kubevela/pkg v0.0.0-20221024115939-a103acee6db2/go.mod h1:TgIGEB/r0NOy63Jzem7WsL3AIr34l+ClH9dmPqcZ4d4= github.com/kubevela/prism v1.5.1-0.20220915071949-6bf3ad33f84f h1:1lUtU1alPThdcsn4MI6XjPb7eJLuZPpmlEdgjtnUMKw= github.com/kubevela/prism v1.5.1-0.20220915071949-6bf3ad33f84f/go.mod h1:m724/7ANnB/iukyHW20+DicpeJMEC/JA0ZhgsHY10MA= -github.com/kubevela/workflow v0.3.4 h1:cI1qeTyOfr1pWbkC40t5aEmEdgZl+m1hI8qvd6Woy30= -github.com/kubevela/workflow v0.3.4/go.mod h1:5jfZ8T1m/En44wDGRf2YqCSlODfEnAV+9PnzoLoDlFs= +github.com/kubevela/workflow v0.3.5-0.20221115021445-48df288898ad h1:WLqg7iMrwvE7O4b0zRJCxoBzbUXv5aJpC5chqd4JdC4= +github.com/kubevela/workflow v0.3.5-0.20221115021445-48df288898ad/go.mod h1:5jfZ8T1m/En44wDGRf2YqCSlODfEnAV+9PnzoLoDlFs= github.com/kulti/thelper v0.4.0/go.mod h1:vMu2Cizjy/grP+jmsvOFDx1kYP6+PD1lqg4Yu5exl2U= github.com/kunwardeep/paralleltest v1.0.3/go.mod h1:vLydzomDFpk7yu5UX02RmP0H8QfRPOV/oFhWN85Mjb4= github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= diff --git a/pkg/controller/core.oam.dev/v1alpha2/application/application_controller_test.go b/pkg/controller/core.oam.dev/v1alpha2/application/application_controller_test.go index a3268c27d..d1438a3fc 100644 --- a/pkg/controller/core.oam.dev/v1alpha2/application/application_controller_test.go +++ b/pkg/controller/core.oam.dev/v1alpha2/application/application_controller_test.go @@ -1559,6 +1559,79 @@ var _ = Describe("Test Application Controller", func() { Expect(checkApp.Status.Phase).Should(BeEquivalentTo(common.ApplicationRunning)) }) + It("application with array inputs", func() { + ns := corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "app-with-array-inputs", + }, + } + Expect(k8sClient.Create(ctx, &ns)).Should(BeNil()) + healthComponentDef := &v1beta1.ComponentDefinition{} + hCDefJson, _ := yaml.YAMLToJSON([]byte(cdDefWithHealthStatusYaml)) + Expect(json.Unmarshal(hCDefJson, healthComponentDef)).Should(BeNil()) + healthComponentDef.Name = "worker-with-health" + healthComponentDef.Namespace = "app-with-array-inputs" + Expect(k8sClient.Create(ctx, healthComponentDef)).Should(BeNil()) + app := &v1beta1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "core.oam.dev/v1beta1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "app-with-array-inputs", + Namespace: "app-with-array-inputs", + }, + Spec: v1beta1.ApplicationSpec{ + Components: []common.ApplicationComponent{ + { + Name: "myweb1", + Type: "worker-with-health", + Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox","lives": "i am lives","enemies": "empty"}`)}, + Outputs: workflowv1alpha1.StepOutputs{ + { + Name: "output", + ValueFrom: "context.name", + }, + }, + }, + { + Name: "myweb2", + Type: "worker", + Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep"],"image":"busybox"}`)}, + Inputs: workflowv1alpha1.StepInputs{ + { + From: "output", + ParameterKey: "cmd[1]", + }, + }, + }, + }, + }, + } + + Expect(k8sClient.Create(context.Background(), app)).Should(BeNil()) + appKey := types.NamespacedName{Namespace: ns.Name, Name: app.Name} + testutil.ReconcileOnce(reconciler, reconcile.Request{NamespacedName: appKey}) + testutil.ReconcileOnce(reconciler, reconcile.Request{NamespacedName: appKey}) + + expDeployment := &v1.Deployment{} + web1Key := types.NamespacedName{Namespace: ns.Name, Name: "myweb1"} + Expect(k8sClient.Get(ctx, web1Key, expDeployment)).Should(BeNil()) + expDeployment.Status.Replicas = 1 + expDeployment.Status.ReadyReplicas = 1 + Expect(k8sClient.Status().Update(ctx, expDeployment)).Should(BeNil()) + web2Key := types.NamespacedName{Namespace: ns.Name, Name: "myweb2"} + Expect(k8sClient.Get(ctx, web2Key, expDeployment)).Should(util.NotFoundMatcher{}) + + testutil.ReconcileOnce(reconciler, reconcile.Request{NamespacedName: appKey}) + + Expect(k8sClient.Get(ctx, web2Key, expDeployment)).Should(BeNil()) + + checkApp := &v1beta1.Application{} + Expect(k8sClient.Get(ctx, appKey, checkApp)).Should(BeNil()) + Expect(checkApp.Status.Phase).Should(BeEquivalentTo(common.ApplicationRunning)) + }) + It("application with timeout outputs in workflow", func() { ns := corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -1835,6 +1908,99 @@ var _ = Describe("Test Application Controller", func() { Expect(checkApp.Status.Phase).Should(BeEquivalentTo(common.ApplicationRunningWorkflow)) }) + It("application with error inputs in workflow", func() { + ns := corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "app-with-error-input", + }, + } + Expect(k8sClient.Create(ctx, &ns)).Should(BeNil()) + healthComponentDef := &v1beta1.ComponentDefinition{} + hCDefJson, _ := yaml.YAMLToJSON([]byte(cdDefWithHealthStatusYaml)) + Expect(json.Unmarshal(hCDefJson, healthComponentDef)).Should(BeNil()) + healthComponentDef.Name = "worker-with-health" + healthComponentDef.Namespace = "app-with-error-input" + Expect(k8sClient.Create(ctx, healthComponentDef)).Should(BeNil()) + app := &v1beta1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "core.oam.dev/v1beta1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "app-with-error-input", + Namespace: "app-with-error-input", + }, + Spec: v1beta1.ApplicationSpec{ + Components: []common.ApplicationComponent{ + { + Name: "myweb1", + Type: "worker-with-health", + Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox","lives": "i am lives","enemies": "empty"}`)}, + }, + { + Name: "myweb2", + Type: "worker", + Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)}, + }, + }, + Workflow: &v1beta1.Workflow{ + Steps: []workflowv1alpha1.WorkflowStep{ + { + WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{ + Name: "myweb1", + Type: "apply-component", + Outputs: workflowv1alpha1.StepOutputs{ + { + Name: "output", + ValueFrom: "context.namespace", + }, + }, + Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb1"}`)}, + }, + }, + { + WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{ + Name: "myweb2", + Inputs: workflowv1alpha1.StepInputs{ + { + From: "output", + ParameterKey: "cmd", + }, + }, + Type: "apply-component", + Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb2"}`)}, + }, + }, + }, + }, + }, + } + + Expect(k8sClient.Create(context.Background(), app)).Should(BeNil()) + appKey := types.NamespacedName{Namespace: ns.Name, Name: app.Name} + testutil.ReconcileOnce(reconciler, reconcile.Request{NamespacedName: appKey}) + testutil.ReconcileOnce(reconciler, reconcile.Request{NamespacedName: appKey}) + + expDeployment := &v1.Deployment{} + web1Key := types.NamespacedName{Namespace: ns.Name, Name: "myweb1"} + Expect(k8sClient.Get(ctx, web1Key, expDeployment)).Should(BeNil()) + expDeployment.Status.Replicas = 1 + expDeployment.Status.ReadyReplicas = 1 + Expect(k8sClient.Status().Update(ctx, expDeployment)).Should(BeNil()) + web2Key := types.NamespacedName{Namespace: ns.Name, Name: "myweb2"} + Expect(k8sClient.Get(ctx, web2Key, expDeployment)).Should(util.NotFoundMatcher{}) + + testutil.ReconcileOnce(reconciler, reconcile.Request{NamespacedName: appKey}) + + Expect(k8sClient.Get(ctx, web2Key, expDeployment)).Should(util.NotFoundMatcher{}) + + checkApp := &v1beta1.Application{} + Expect(k8sClient.Get(ctx, appKey, checkApp)).Should(BeNil()) + Expect(checkApp.Status.Workflow.Steps[0].Phase).Should(BeEquivalentTo(workflowv1alpha1.WorkflowStepPhaseSucceeded)) + Expect(checkApp.Status.Workflow.Steps[1].Phase).Should(BeEquivalentTo(workflowv1alpha1.WorkflowStepPhaseFailed)) + Expect(checkApp.Status.Phase).Should(BeEquivalentTo(common.ApplicationWorkflowFailed)) + }) + It("application with invalid inputs in workflow in dag mode", func() { ns := corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ diff --git a/references/cli/status.go b/references/cli/status.go index fbf2281c5..d38ee55ef 100644 --- a/references/cli/status.go +++ b/references/cli/status.go @@ -287,7 +287,7 @@ func printWorkflowStatus(c client.Client, ioStreams cmdutil.IOStreams, appName s } } } - if remoteApp.Status.Workflow != nil { + if remoteApp.Status.Workflow != nil && remoteApp.Status.Workflow.ContextBackend != nil { ctxBackend := remoteApp.Status.Workflow.ContextBackend v, err = utils.GetDataFromContext(context.Background(), c, ctxBackend.Name, remoteApp.Name, remoteApp.Namespace) if err != nil {