Merge pull request #1092 from wonderflow/outputs

output not allowed in traitdefinition, should use outputs
This commit is contained in:
Jianbo Sun
2021-02-24 19:39:01 +08:00
committed by GitHub
17 changed files with 45 additions and 60 deletions
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+5 -3
View File
@@ -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
+1 -1
View File
@@ -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
+7 -6
View File
@@ -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
View File
@@ -1,4 +1,4 @@
output: {
outputs: scaler: {
apiVersion: "core.oam.dev/v1alpha2"
kind: "ManualScalerTrait"
spec: {
+1 -1
View File
@@ -1,4 +1,4 @@
output: {
outputs: rollout: {
apiVersion: "extend.oam.dev/v1alpha2"
kind: "SimpleRolloutTrait"
spec: {
+1 -1
View File
@@ -1,4 +1,4 @@
output: {
outputs: ingress: {
apiVersion: "networking.k8s.io/v1beta1"
kind: "Ingress"
spec: {
+1 -1
View File
@@ -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: {
+3 -15
View File
@@ -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
+5 -5
View File
@@ -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)
}
}
}
+2 -9
View File
@@ -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"))
+2 -3
View File
@@ -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
View File
@@ -12,7 +12,7 @@ spec:
workloadRefPath: spec.workloadRef
extension:
template: |-
output: {
outputs: scaler: {
apiVersion: "core.oam.dev/v1alpha2"
kind: "ManualScalerTrait"
spec: {
+1 -1
View File
@@ -9,7 +9,7 @@ spec:
name: routes.standard.oam.dev
extension:
template: |
output: {
outputs: route: {
spec: {
domain: parameter.domain
}