diff --git a/config/samples/application/README.md b/config/samples/application/README.md index f4c8afc70..8469857e7 100644 --- a/config/samples/application/README.md +++ b/config/samples/application/README.md @@ -158,7 +158,7 @@ spec: extension: template: |- patch: {spec: template: metadata: labels: app: context.name} - output: { + outputs: service: { apiVersion: "v1" kind: "Service" metadata: name: context.name diff --git a/config/samples/application/template.yaml b/config/samples/application/template.yaml index 6a073ff66..c50afd63d 100644 --- a/config/samples/application/template.yaml +++ b/config/samples/application/template.yaml @@ -103,7 +103,7 @@ spec: extension: template: |- patch: {spec: template: metadata: labels: app: context.name} - output: { + outputs: service: { apiVersion: "v1" kind: "Service" metadata: name: context.name diff --git a/docs/en/cue/trait.md b/docs/en/cue/trait.md index f5f2b2e1d..fd2934da8 100644 --- a/docs/en/cue/trait.md +++ b/docs/en/cue/trait.md @@ -4,9 +4,10 @@ In this section we will introduce how to define a Trait with CUE template. ## Composition -Defining a *Trait* with CUE template is a bit different from *Workload Type*: a trait MUST use `outputs` keyword instead of `output` to define template. +Defining a *Trait* with CUE template is a bit different from *Workload Type*: a trait MUST use `outputs` keyword instead of `output` in template. -With the help of CUE template, it is very nature to compose multiple Kubernetes resources in one trait. Similarly, the format MUST be `outputs::`. +With the help of CUE template, it is very nature to compose multiple Kubernetes resources in one trait. +Similarly, the format MUST be `outputs::`. Below is an example for `ingress` trait. @@ -147,7 +148,7 @@ spec: ## Patch Trait -You could also use keyword `patch` to patch data to the component instance (before the resource is applied) and claim this behavior as a trait. +You could also use keyword `patch` to patch data to the component instance (before the resource applied) and claim this behavior as a trait. Below is an example for `node-affinity` trait: @@ -356,6 +357,7 @@ please make sure the trait resource name is unique, or the former data will be c Below is an example 1. the main workload object(Deployment) in this example will render into the context.output before rendering traits. 2. the context.outputs. will keep all these rendered trait data and can be used in the traits after them. + ```yaml apiVersion: core.oam.dev/v1alpha2 kind: WorkloadDefinition diff --git a/docs/en/platform-engineers/trait.md b/docs/en/platform-engineers/trait.md index 6ca6e969b..1ec6be7e3 100644 --- a/docs/en/platform-engineers/trait.md +++ b/docs/en/platform-engineers/trait.md @@ -106,7 +106,7 @@ Platform builders only need to declare this info here once, then the OAM framewo ```yaml ... template: | - output: { + outputs: kubewatch: { apiVersion: "labs.bitnami.com/v1alpha1" kind: "KubeWatch" spec: handler: webhook: url: parameter.webhook diff --git a/pkg/appfile/parser_test.go b/pkg/appfile/parser_test.go index 00e5ca8c8..8402fa494 100644 --- a/pkg/appfile/parser_test.go +++ b/pkg/appfile/parser_test.go @@ -96,7 +96,7 @@ var expectedExceptApp = &Appfile{ "replicas": float64(10), }, Template: ` - output: { + outputs:scaler: { apiVersion: "core.oam.dev/v1alpha2" kind: "ManualScalerTrait" spec: { @@ -130,7 +130,7 @@ spec: workloadRefPath: spec.workloadRef extension: template: |- - output: { + outputs: scaler: { apiVersion: "core.oam.dev/v1alpha2" kind: "ManualScalerTrait" spec: { @@ -344,7 +344,7 @@ var _ = Describe("Test appFile parser", func() { "replicas": float64(10), }, Template: ` - output: { + outputs: scaler: { apiVersion: "core.oam.dev/v1alpha2" kind: "ManualScalerTrait" spec: { @@ -376,9 +376,10 @@ var _ = Describe("Test appFile parser", func() { "kind": "ManualScalerTrait", "metadata": map[string]interface{}{ "labels": map[string]interface{}{ - "app.oam.dev/component": "myweb", - "app.oam.dev/name": "test", - "trait.oam.dev/type": "scaler", + "app.oam.dev/component": "myweb", + "app.oam.dev/name": "test", + "trait.oam.dev/type": "scaler", + "trait.oam.dev/resource": "scaler", }, }, "spec": map[string]interface{}{"replicaCount": int64(10)}, 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 9a1434a1f..76a862be2 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 @@ -132,9 +132,10 @@ var _ = Describe("Test Application Controller", func() { "kind": "ManualScalerTrait", "metadata": map[string]interface{}{ "labels": map[string]interface{}{ - "trait.oam.dev/type": "scaler", - "app.oam.dev/component": compName, - "app.oam.dev/name": appName, + "trait.oam.dev/type": "scaler", + "app.oam.dev/component": compName, + "app.oam.dev/name": appName, + "trait.oam.dev/resource": "scaler", }, }, "spec": map[string]interface{}{ @@ -741,9 +742,10 @@ var _ = Describe("Test Application Controller", func() { expTrait.SetName(app.Name) expTrait.SetNamespace(app.Namespace) expTrait.SetLabels(map[string]string{ - oam.LabelAppName: app.Name, - "trait.oam.dev/type": "scaler", - "app.oam.dev/component": "myweb-health", + oam.LabelAppName: app.Name, + "trait.oam.dev/type": "scaler", + "app.oam.dev/component": "myweb-health", + "trait.oam.dev/resource": "scaler", }) (expTrait.Object["spec"].(map[string]interface{}))["workloadRef"] = map[string]interface{}{ "apiVersion": "apps/v1", @@ -1369,7 +1371,7 @@ spec: workloadRefPath: spec.workloadRef extension: template: |- - output: { + outputs: scaler: { apiVersion: "core.oam.dev/v1alpha2" kind: "ManualScalerTrait" spec: { @@ -1398,7 +1400,7 @@ spec: workloadRefPath: spec.workloadRef extension: template: |- - output: { + outputs: scaler: { apiVersion: "core.oam.dev/v1alpha2" kind: "ManualScalerTrait" spec: { @@ -1444,7 +1446,7 @@ spec: healthPolicy: | isHealth: context.output.status.conditions[0].status == "True" template: |- - output: { + outputs: scaler: { apiVersion: "core.oam.dev/v1alpha2" kind: "ManualScalerTrait" spec: { diff --git a/pkg/cue/testdata/traits/manualscaler.cue b/pkg/cue/testdata/traits/manualscaler.cue index 59f5af545..45dd37a24 100644 --- a/pkg/cue/testdata/traits/manualscaler.cue +++ b/pkg/cue/testdata/traits/manualscaler.cue @@ -1,4 +1,4 @@ -output: { +outputs: scaler: { apiVersion: "core.oam.dev/v1alpha2" kind: "ManualScalerTrait" spec: { diff --git a/pkg/cue/testdata/traits/rollout.cue b/pkg/cue/testdata/traits/rollout.cue index 5481f32b5..747e44f7d 100644 --- a/pkg/cue/testdata/traits/rollout.cue +++ b/pkg/cue/testdata/traits/rollout.cue @@ -1,4 +1,4 @@ -output: { +outputs: rollout: { apiVersion: "extend.oam.dev/v1alpha2" kind: "SimpleRolloutTrait" spec: { diff --git a/pkg/cue/testdata/traits/route.cue b/pkg/cue/testdata/traits/route.cue index 6121716d5..1d697596d 100644 --- a/pkg/cue/testdata/traits/route.cue +++ b/pkg/cue/testdata/traits/route.cue @@ -1,4 +1,4 @@ -output: { +outputs: ingress: { apiVersion: "networking.k8s.io/v1beta1" kind: "Ingress" spec: { diff --git a/pkg/cue/testdata/workloads/metrics.cue b/pkg/cue/testdata/workloads/metrics.cue index e8ea06b9f..3859f08a7 100644 --- a/pkg/cue/testdata/workloads/metrics.cue +++ b/pkg/cue/testdata/workloads/metrics.cue @@ -7,7 +7,7 @@ // +usage=the label selector for the pods, default is the workload labels selector?: [string]: string } -output: { +outputs: metrics: { apiVersion: "standard.oam.dev/v1alpha1" kind: "MetricsTrait" spec: { diff --git a/pkg/dsl/definition/template.go b/pkg/dsl/definition/template.go index b2d999753..87cb4bea8 100644 --- a/pkg/dsl/definition/template.go +++ b/pkg/dsl/definition/template.go @@ -119,7 +119,7 @@ func (wd *workloadDef) Complete(ctx process.Context, abstractTemplate string) er if err != nil { return errors.WithMessagef(err, "invalid outputs(%s) of workload %s", fieldInfo.Name, wd.name) } - ctx.AppendAuxiliaries(process.Auxiliary{Ins: other, Type: AuxiliaryWorkload, Name: fieldInfo.Name, IsOutputs: true}) + ctx.AppendAuxiliaries(process.Auxiliary{Ins: other, Type: AuxiliaryWorkload, Name: fieldInfo.Name}) } } return nil @@ -291,14 +291,6 @@ func (td *traitDef) Complete(ctx process.Context, abstractTemplate string) error } } - output := inst.Lookup(OutputFieldName) - if output.Exists() { - other, err := model.NewOther(output) - if err != nil { - return errors.WithMessagef(err, "invalid output of trait %s", td.name) - } - ctx.AppendAuxiliaries(process.Auxiliary{Ins: other, Type: td.name, IsOutputs: false}) - } outputs := inst.Lookup(OutputsFieldName) if outputs.Exists() { st, err := outputs.Struct() @@ -314,7 +306,7 @@ func (td *traitDef) Complete(ctx process.Context, abstractTemplate string) error if err != nil { return errors.WithMessagef(err, "invalid outputs(resource=%s) of trait %s", fieldInfo.Name, td.name) } - ctx.AppendAuxiliaries(process.Auxiliary{Ins: other, Type: td.name, Name: fieldInfo.Name, IsOutputs: true}) + ctx.AppendAuxiliaries(process.Auxiliary{Ins: other, Type: td.name, Name: fieldInfo.Name}) } } @@ -361,11 +353,7 @@ func (td *traitDef) getTemplateContext(ctx process.Context, cli client.Reader, n if err != nil { return nil, err } - if assist.IsOutputs { - outputs[assist.Name] = object - } else { - root[OutputFieldName] = object - } + outputs[assist.Name] = object } if len(outputs) > 0 { root[OutputsFieldName] = outputs diff --git a/pkg/dsl/definition/template_test.go b/pkg/dsl/definition/template_test.go index 8719272f7..f013b5ffb 100644 --- a/pkg/dsl/definition/template_test.go +++ b/pkg/dsl/definition/template_test.go @@ -160,7 +160,7 @@ parameter: { }, "output trait": { traitTemplate: ` -output: { +outputs: service: { apiVersion: "v1" kind: "Service" metadata: name: context.name @@ -202,12 +202,12 @@ parameter: { "kind": "ConfigMap", "metadata": map[string]interface{}{"name": "testgame-config"}, "data": map[string]interface{}{"enemies": "enemies-data", "lives": "lives-data"}}, }, - "t1": &unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "v1", "kind": "Service", "metadata": map[string]interface{}{"name": "test"}, "spec": map[string]interface{}{"type": "ClusterIP"}}}, + "t1service": &unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "v1", "kind": "Service", "metadata": map[string]interface{}{"name": "test"}, "spec": map[string]interface{}{"type": "ClusterIP"}}}, }, }, "outputs trait": { traitTemplate: ` -output: { +outputs: service: { apiVersion: "v1" kind: "Service" metadata: name: context.name @@ -257,7 +257,7 @@ parameter: { "kind": "ConfigMap", "metadata": map[string]interface{}{"name": "testgame-config"}, "data": map[string]interface{}{"enemies": "enemies-data", "lives": "lives-data"}}, }, - "t2": &unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "v1", "kind": "Service", "metadata": map[string]interface{}{"name": "test"}, "spec": map[string]interface{}{"type": "ClusterIP"}}}, + "t2service": &unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "v1", "kind": "Service", "metadata": map[string]interface{}{"name": "test"}, "spec": map[string]interface{}{"type": "ClusterIP"}}}, "t2ingress": &unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "extensions/v1beta1", "kind": "Ingress", "metadata": map[string]interface{}{"name": "test"}, "spec": map[string]interface{}{"rules": []interface{}{map[string]interface{}{ "host": "example.com", }}}}}, @@ -425,7 +425,7 @@ parameter: { for _, ss := range assists { got, err := ss.Ins.Unstructured() assert.NoError(t, err, cassinfo) - assert.Equal(t, v.expAssObjs[ss.Type+ss.Name], got, cassinfo, ss.Type+ss.Name) + assert.Equal(t, v.expAssObjs[ss.Type+ss.Name], got, "case %s , type: %s name: %s", cassinfo, ss.Type, ss.Name) } } } diff --git a/pkg/dsl/process/handle.go b/pkg/dsl/process/handle.go index 6d123802b..260350ba7 100644 --- a/pkg/dsl/process/handle.go +++ b/pkg/dsl/process/handle.go @@ -33,6 +33,7 @@ type Context interface { } // Auxiliary are objects rendered by definition template. +// the format for auxiliary resource is always: `outputs.`, it can be auxiliary workload or trait type Auxiliary struct { Ins model.Instance // Type will be used to mark definition label for OAM runtime to get the CRD @@ -41,12 +42,6 @@ type Auxiliary struct { // Workload or trait with multiple `outputs` will have a name, if name is empty, than it's the main of this type. Name string - - // IsOutputs will record the output path format of the Auxiliary - // it can be one of these two cases: - // false: the format is `output`, this means it's the main resource of the trait - // true: the format is `outputs.`, this means it can be auxiliary workload or trait - IsOutputs bool } type templateContext struct { @@ -99,9 +94,7 @@ func (ctx *templateContext) BaseContextFile() string { if len(ctx.auxiliaries) > 0 { var auxLines []string for _, auxiliary := range ctx.auxiliaries { - if auxiliary.IsOutputs { - auxLines = append(auxLines, fmt.Sprintf("%s: %s", auxiliary.Name, structMarshal(auxiliary.Ins.String()))) - } + auxLines = append(auxLines, fmt.Sprintf("%s: %s", auxiliary.Name, structMarshal(auxiliary.Ins.String()))) } if len(auxLines) > 0 { buff += fmt.Sprintf(OutputsFieldName+": {%s}\n", strings.Join(auxLines, "\n")) diff --git a/pkg/dsl/process/handle_test.go b/pkg/dsl/process/handle_test.go index 3cc844c4d..e3410b76d 100644 --- a/pkg/dsl/process/handle_test.go +++ b/pkg/dsl/process/handle_test.go @@ -44,9 +44,8 @@ image: "myserver" } svcAux := Auxiliary{ - Ins: svcIns, - Name: "service", - IsOutputs: true, + Ins: svcIns, + Name: "service", } ctx := NewContext("mycomp", "myapp") diff --git a/pkg/webhook/core.oam.dev/v1alpha2/application/suite_test.go b/pkg/webhook/core.oam.dev/v1alpha2/application/suite_test.go index 142c0d42b..8a36e562d 100644 --- a/pkg/webhook/core.oam.dev/v1alpha2/application/suite_test.go +++ b/pkg/webhook/core.oam.dev/v1alpha2/application/suite_test.go @@ -172,7 +172,7 @@ spec: workloadRefPath: spec.workloadRef extension: template: |- - output: { + outputs: scaler: { apiVersion: "core.oam.dev/v1alpha2" kind: "ManualScalerTrait" spec: { diff --git a/references/plugins/testdata/manualscalars.yaml b/references/plugins/testdata/manualscalars.yaml index 6a4283aa5..8103acb70 100644 --- a/references/plugins/testdata/manualscalars.yaml +++ b/references/plugins/testdata/manualscalars.yaml @@ -12,7 +12,7 @@ spec: workloadRefPath: spec.workloadRef extension: template: |- - output: { + outputs: scaler: { apiVersion: "core.oam.dev/v1alpha2" kind: "ManualScalerTrait" spec: { diff --git a/references/plugins/testdata/traitDef.yaml b/references/plugins/testdata/traitDef.yaml index d5569fb21..d311d31e4 100644 --- a/references/plugins/testdata/traitDef.yaml +++ b/references/plugins/testdata/traitDef.yaml @@ -9,7 +9,7 @@ spec: name: routes.standard.oam.dev extension: template: | - output: { + outputs: route: { spec: { domain: parameter.domain }