add hpa trait and fix template without params (#1279)

This commit is contained in:
Jianbo Sun
2021-03-24 16:18:58 +08:00
committed by GitHub
parent b6218bf67d
commit 9366c6e0b4
5 changed files with 196 additions and 6 deletions
+44 -1
View File
@@ -86,7 +86,50 @@ Hence, the `settings` section of `backend` only supports two parameters: `image`
The similar extensible abstraction mechanism also applies to traits. For example, `name: autoscaler` in `frontend` means its trait specification (i.e. `properties` section) will be enforced by a `TraitDefinition` object named `autoscaler` as below:
> TBD: a autoscaler TraitDefinition (HPA)
```yaml
apiVersion: core.oam.dev/v1alpha2
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: "configure k8s HPA for Deployment"
name: hpa
spec:
appliesToWorkloads:
- webservice
- worker
schematic:
cue:
template: |
outputs: hpa: {
apiVersion: "autoscaling/v2beta2"
kind: "HorizontalPodAutoscaler"
metadata: name: context.name
spec: {
scaleTargetRef: {
apiVersion: "apps/v1"
kind: "Deployment"
name: context.name
}
minReplicas: parameter.min
maxReplicas: parameter.max
metrics: [{
type: "Resource"
resource: {
name: "cpu"
target: {
type: "Utilization"
averageUtilization: parameter.cpuUtil
}
}
}]
}
}
parameter: {
min: *1 | int
max: *10 | int
cpuUtil: *50 | int
}
```
All the definition objects are expected to be defined and installed by platform team. The end users will only focus on `Application` resource (either render it by tools or author it manually).
+29
View File
@@ -0,0 +1,29 @@
outputs: hpa: {
apiVersion: "autoscaling/v2beta2"
kind: "HorizontalPodAutoscaler"
metadata: name: context.name
spec: {
scaleTargetRef: {
apiVersion: "apps/v1"
kind: "Deployment"
name: context.name
}
minReplicas: parameter.min
maxReplicas: parameter.max
metrics: [{
type: "Resource"
resource: {
name: "cpu"
target: {
type: "Utilization"
averageUtilization: parameter.cpuUtil
}
}
}]
}
}
parameter: {
min: *1 | int
max: *10 | int
cpuUtil: *50 | int
}
+43
View File
@@ -0,0 +1,43 @@
apiVersion: core.oam.dev/v1alpha2
kind: TraitDefinition
metadata:
annotations:
definition.oam.dev/description: "configure k8s HPA for Deployment"
name: hpa
spec:
appliesToWorkloads:
- webservice
- worker
schematic:
cue:
template: |
outputs: hpa: {
apiVersion: "autoscaling/v2beta2"
kind: "HorizontalPodAutoscaler"
metadata: name: context.name
spec: {
scaleTargetRef: {
apiVersion: "apps/v1"
kind: "Deployment"
name: context.name
}
minReplicas: parameter.min
maxReplicas: parameter.max
metrics: [{
type: "Resource"
resource: {
name: "cpu"
target: {
type: "Utilization"
averageUtilization: parameter.cpuUtil
}
}
}]
}
}
parameter: {
min: *1 | int
max: *10 | int
cpuUtil: *50 | int
}
+12 -5
View File
@@ -69,15 +69,19 @@ func (wd *workloadDef) Complete(ctx process.Context, abstractTemplate string, pa
if err := bi.AddFile("-", abstractTemplate); err != nil {
return errors.WithMessagef(err, "invalid cue template of workload %s", wd.name)
}
var paramFile = "parameter: {}"
if params != nil {
bt, err := json.Marshal(params)
if err != nil {
return errors.WithMessagef(err, "marshal parameter of workload %s", wd.name)
}
if err := bi.AddFile("parameter", fmt.Sprintf("parameter: %s", string(bt))); err != nil {
return errors.WithMessagef(err, "invalid parameter of workload %s", wd.name)
if string(bt) != "null" {
paramFile = fmt.Sprintf("parameter: %s", string(bt))
}
}
if err := bi.AddFile("parameter", paramFile); err != nil {
return errors.WithMessagef(err, "invalid parameter of workload %s", wd.name)
}
if err := bi.AddFile("-", ctx.BaseContextFile()); err != nil {
return err
@@ -248,16 +252,19 @@ func (td *traitDef) Complete(ctx process.Context, abstractTemplate string, param
if err := bi.AddFile("-", abstractTemplate); err != nil {
return errors.WithMessagef(err, "invalid template of trait %s", td.name)
}
var paramFile = "parameter: {}"
if params != nil {
bt, err := json.Marshal(params)
if err != nil {
return errors.WithMessagef(err, "marshal parameter of trait %s", td.name)
}
if err := bi.AddFile("parameter", fmt.Sprintf("parameter: %s", string(bt))); err != nil {
return errors.WithMessagef(err, "invalid parameter of trait %s", td.name)
if string(bt) != "null" {
paramFile = fmt.Sprintf("parameter: %s", string(bt))
}
}
if err := bi.AddFile("parameter", paramFile); err != nil {
return errors.WithMessagef(err, "invalid parameter of trait %s", td.name)
}
if err := bi.AddFile("context", ctx.BaseContextFile()); err != nil {
return errors.WithMessagef(err, "invalid context of trait %s", td.name)
}
+68
View File
@@ -103,6 +103,23 @@ parameter: {
},
expectObj: &unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{"name": "test", "annotations": map[string]interface{}{"revision.oam.dev": "myapp-v1"}}, "spec": map[string]interface{}{"replicas": int64(2)}}},
},
{
workloadTemplate: `
output:{
apiVersion: "apps/v1"
kind: "Deployment"
metadata: {
name: context.name
}
spec: replicas: parameter.replicas
}
parameter: {
replicas: *1 | int
}
`,
params: nil,
expectObj: &unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{"name": "test"}, "spec": map[string]interface{}{"replicas": int64(1)}}},
},
}
for _, v := range testCases {
@@ -496,6 +513,57 @@ parameter: {
"t2ingress": &unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "extensions/v1beta1", "kind": "Ingress"}},
},
},
"outputs trait with no params": {
traitTemplate: `
outputs: hpa: {
apiVersion: "autoscaling/v2beta2"
kind: "HorizontalPodAutoscaler"
metadata: name: context.name
spec: {
minReplicas: parameter.min
maxReplicas: parameter.max
}
}
parameter: {
min: *1 | int
max: *10 | int
}`,
params: nil,
expWorkload: &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"spec": map[string]interface{}{
"replicas": int64(2),
"selector": map[string]interface{}{
"matchLabels": map[string]interface{}{
"app.oam.dev/component": "test"}},
"template": map[string]interface{}{
"metadata": map[string]interface{}{
"labels": map[string]interface{}{"app.oam.dev/component": "test"},
},
"spec": map[string]interface{}{
"containers": []interface{}{map[string]interface{}{
"envFrom": []interface{}{map[string]interface{}{
"configMapRef": map[string]interface{}{"name": "testgame-config"},
}},
"image": "website:0.1",
"name": "main",
"ports": []interface{}{map[string]interface{}{"containerPort": int64(443)}}}}}}}},
},
traitName: "t2",
expAssObjs: map[string]runtime.Object{
"AuxiliaryWorkloadgameconfig": &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{"name": "testgame-config"}, "data": map[string]interface{}{"enemies": "enemies-data", "lives": "lives-data"}},
},
"t2hpa": &unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": "autoscaling/v2beta2", "kind": "HorizontalPodAutoscaler",
"metadata": map[string]interface{}{"name": "test"},
"spec": map[string]interface{}{"maxReplicas": int64(10), "minReplicas": int64(1)}}},
},
},
}
for cassinfo, v := range tds {