mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-19 04:26:39 +00:00
Merge pull request #1092 from wonderflow/outputs
output not allowed in traitdefinition, should use outputs
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:<unique-name>:<full 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:<unique-name>:<full template>`.
|
||||
|
||||
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.<xx> will keep all these rendered trait data and can be used in the traits after them.
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: WorkloadDefinition
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)},
|
||||
|
||||
@@ -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: {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
output: {
|
||||
outputs: scaler: {
|
||||
apiVersion: "core.oam.dev/v1alpha2"
|
||||
kind: "ManualScalerTrait"
|
||||
spec: {
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
output: {
|
||||
outputs: rollout: {
|
||||
apiVersion: "extend.oam.dev/v1alpha2"
|
||||
kind: "SimpleRolloutTrait"
|
||||
spec: {
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
output: {
|
||||
outputs: ingress: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
kind: "Ingress"
|
||||
spec: {
|
||||
|
||||
+1
-1
@@ -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: {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ type Context interface {
|
||||
}
|
||||
|
||||
// Auxiliary are objects rendered by definition template.
|
||||
// the format for auxiliary resource is always: `outputs.<resourceName>`, 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.<resourceName>`, 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"))
|
||||
|
||||
@@ -44,9 +44,8 @@ image: "myserver"
|
||||
}
|
||||
|
||||
svcAux := Auxiliary{
|
||||
Ins: svcIns,
|
||||
Name: "service",
|
||||
IsOutputs: true,
|
||||
Ins: svcIns,
|
||||
Name: "service",
|
||||
}
|
||||
|
||||
ctx := NewContext("mycomp", "myapp")
|
||||
|
||||
@@ -172,7 +172,7 @@ spec:
|
||||
workloadRefPath: spec.workloadRef
|
||||
extension:
|
||||
template: |-
|
||||
output: {
|
||||
outputs: scaler: {
|
||||
apiVersion: "core.oam.dev/v1alpha2"
|
||||
kind: "ManualScalerTrait"
|
||||
spec: {
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ spec:
|
||||
workloadRefPath: spec.workloadRef
|
||||
extension:
|
||||
template: |-
|
||||
output: {
|
||||
outputs: scaler: {
|
||||
apiVersion: "core.oam.dev/v1alpha2"
|
||||
kind: "ManualScalerTrait"
|
||||
spec: {
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ spec:
|
||||
name: routes.standard.oam.dev
|
||||
extension:
|
||||
template: |
|
||||
output: {
|
||||
outputs: route: {
|
||||
spec: {
|
||||
domain: parameter.domain
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user