diff --git a/api/types/capability.go b/api/types/capability.go index 7075dd561..22eea0404 100644 --- a/api/types/capability.go +++ b/api/types/capability.go @@ -85,6 +85,7 @@ type Parameter struct { Default interface{} `json:"default,omitempty"` Usage string `json:"usage,omitempty"` Type cue.Kind `json:"type,omitempty"` + Alias string `json:"alias,omitempty"` } // ConvertTemplateJSON2Object convert spec.extension to object @@ -105,6 +106,10 @@ func ConvertTemplateJSON2Object(in *runtime.RawExtension) (Capability, error) { } func SetFlagBy(flags *pflag.FlagSet, v Parameter) { + name := v.Name + if v.Alias != "" { + name = v.Alias + } switch v.Type { case cue.IntKind: var vv int64 @@ -118,11 +123,11 @@ func SetFlagBy(flags *pflag.FlagSet, v Parameter) { case float64: vv = int64(val) } - flags.Int64P(v.Name, v.Short, vv, v.Usage) + flags.Int64P(name, v.Short, vv, v.Usage) case cue.StringKind: - flags.StringP(v.Name, v.Short, v.Default.(string), v.Usage) + flags.StringP(name, v.Short, v.Default.(string), v.Usage) case cue.BoolKind: - flags.BoolP(v.Name, v.Short, v.Default.(bool), v.Usage) + flags.BoolP(name, v.Short, v.Default.(bool), v.Usage) case cue.NumberKind, cue.FloatKind: var vv float64 switch val := v.Default.(type) { @@ -135,7 +140,7 @@ func SetFlagBy(flags *pflag.FlagSet, v Parameter) { case float64: vv = val } - flags.Float64P(v.Name, v.Short, vv, v.Usage) + flags.Float64P(name, v.Short, vv, v.Usage) } } diff --git a/charts/vela-core/templates/defwithtemplate/autoscale.yaml b/charts/vela-core/templates/defwithtemplate/autoscale.yaml index a444f1c5b..50f1cc917 100644 --- a/charts/vela-core/templates/defwithtemplate/autoscale.yaml +++ b/charts/vela-core/templates/defwithtemplate/autoscale.yaml @@ -5,7 +5,7 @@ metadata: annotations: definition.oam.dev/apiVersion: standard.oam.dev/v1alpha1 definition.oam.dev/kind: Autoscaler - definition.oam.dev/description: "Automatically scale workloads by cron or resource utilization" + definition.oam.dev/description: "Automatically scale workloads" spec: appliesToWorkloads: - webservice @@ -18,32 +18,56 @@ spec: extension: template: | output: { - apiVersion: "standard.oam.dev/v1alpha1" - kind: "Autoscaler" - spec: { - minReplicas: parameter.minReplicas - maxReplicas: parameter.maxReplicas - triggers: [{ - name: parameter.name - type: parameter.type - condition: { - startAt: parameter.startAt - duration: parameter.duration - days: parameter.days - replicas: parameter.replicas - timezone: parameter.timezone - } - }, ...] - } - } - parameter: { - minReplicas: *1 | int - maxReplicas: *4 | int - name: *"" | string - type: *"cron" | string - startAt: string - duration: string - days: string - replicas: *"2" | string - timezone: *"Asia/Shanghai" | string + apiVersion: "standard.oam.dev/v1alpha1" + kind: "Autoscaler" + spec: { + minReplicas: parameter.min + maxReplicas: parameter.max + if parameter["cpu"] != _|_ && parameter["cron"] != _|_ { + triggers: [cpuScaler, cronScaler] + } + if parameter["cpu"] != _|_ && parameter["cron"] == _|_ { + triggers: [cpuScaler] + } + if parameter["cpu"] == _|_ && parameter["cron"] != _|_ { + triggers: [cronScaler] + } + } } + + cpuScaler: { + type: "cpu" + condition: { + type: "Utilization" + if parameter["cpu"] != _|_ { + value: parameter.cpu + } + } + } + + cronScaler: { + type: "cron" + if parameter["cron"] != _|_ { + condition: parameter.cron + } + } + + parameter: { + // +usage=minimal replicas of the workload + min: int + // +usage=maximal replicas of the workload + max: int + // +usage=specify the value for CPU utilization, like 80, which means 80% + cpu?: string + // +usage=just for `appfile`, not available for Cli usage + cron?: { + startAt: string + duration: string + // +usage=several workdays or weekends, like "Monday, Tuesday" + days: string + replicas: string + // +usage=timezone, like "America/Seattle" + timezone: string + } + } + diff --git a/charts/vela-core/templates/defwithtemplate/webservice.yaml b/charts/vela-core/templates/defwithtemplate/webservice.yaml index f50c6297e..858a4685e 100644 --- a/charts/vela-core/templates/defwithtemplate/webservice.yaml +++ b/charts/vela-core/templates/defwithtemplate/webservice.yaml @@ -49,8 +49,17 @@ spec: ports: [{ containerPort: parameter.port }] + + if parameter["cpuRequests"] != _|_ { + resources: { + limits: + cpu: parameter.cpuRequests + requests: + cpu: parameter.cpuRequests + } + } }] - } + } } } } @@ -75,5 +84,8 @@ spec: } } }] + // +usage=CPU core requests for the workload + // +alias=cpu-requests + cpuRequests?: string } diff --git a/charts/vela-core/templates/velaConfig.yaml b/charts/vela-core/templates/velaConfig.yaml index d717957f4..5cb96c18f 100644 --- a/charts/vela-core/templates/velaConfig.yaml +++ b/charts/vela-core/templates/velaConfig.yaml @@ -26,5 +26,5 @@ data: "urL": "https://kedacore.github.io/charts", "name": "keda", "namespace": "keda", - "version": "2.0.0-beta1.2" + "version": "2.0.0-rc3" } diff --git a/docs/developers/set-autoscale.md b/docs/developers/set-autoscale.md index 74c636507..9b09d4583 100644 --- a/docs/developers/set-autoscale.md +++ b/docs/developers/set-autoscale.md @@ -1,65 +1,235 @@ -# Automatically scale workload by cron or resource utilization +# Automatically scale workloads by resource utilization metrics and cron -## Prerequisites - - [ ] [KEDA v2.0 Beta](https://keda.sh/blog/keda-2.0-beta/) - - KEDA will be automatically deployed during vela installation, so just run the following command. - ```shell - $ vela install - ``` - -## Scale an application +Contents: +- [Scale by CPU resource utilization metrics](#Scale by CPU resource utilization metrics) +- [Scale workload by cron](#Scale workload by cron) + +## Scale by CPU resource utilization metrics +Introduce how to automatically scale workloads by resource utilization metrics in Cli. Currently, only cpu utilization +is supported. - Deploy an application Run the following command to deploy application `helloworld`. ``` - $ vela svc deploy frontend -t webservice -a helloworld --image nginx:1.9.2 --port 80 + $ vela svc deploy frontend -t webservice -a helloworld --image nginx:1.9.2 --port 80 --cpu-requests=0.05 App helloworld deployed ``` - Check the replicas of Deployment `frontend` which is deployed by workload webservice `helloworld` and there is one replica. - - (TODO: The command below needs to be replaced with `vela show` to check the replicas.) - ``` - $ kubectl get deploy frontend - NAME READY UP-TO-DATE AVAILABLE AGE - frontend 1/1 1 1 2m52s - ``` + By default, the replicas of the workload webservice `helloworld` is. -- Scale the application by `cron` +- Scale the application by CPU utilization metrics ``` - $ vela autoscale helloworld --svc frontend --minReplicas 1 --maxReplicas 4 --replicas 2 --name cron-test --startAt 21:00 --duration 2h --days "Monday, Tuesday" + $ vela autoscale helloworld --svc frontend --min 1 --max 5 --cpu 5 Adding autoscale for app frontend - ⠋ Deploying ... + ⠋ Checking Status ... ✅ Application Deployed Successfully! - Name: frontend Type: webservice HEALTHY Ready: 1/1 - Last Deployment: - Created at: 2020-11-03 20:53:50 +0800 CST - Updated at: 2020-11-03T21:01:20+08:00 Traits: - - autoscale: - maxReplicas=4 - minReplicas=1 - replicas=2 - startAt=21:00 - timezone=Asia/Shanghai - days=Monday, Tuesday - name=cron-test - type=cron - duration=2h + - ✅ autoscale: type: cpu minReplicas: 1 maxReplicas: 5 CPUUtilization(target/current): 5%/0% replicas: 0 + Last Deployment: + Created at: 2020-11-06 16:10:54 +0800 CST + Updated at: 2020-11-06T16:19:04+08:0 ``` - The time is `21:07` which is in the active period of the trait which started at `21:00` and the duration is two hours. - Check the replicas of Deployment `frontend` again, it has been scaled to 2. +- Access the application with heavy requests + ``` - $ kubectl get deploy - NAME READY UP-TO-DATE AVAILABLE AGE - frontend 2/2 2 2 8m42s + $ vela port-forward helloworld 80 + Forwarding from 127.0.0.1:80 -> 80 + Forwarding from [::1]:80 -> 80 + + Forward successfully! Opening browser ... + Handling connection for 80 + Handling connection for 80 + Handling connection for 80 + Handling connection for 80 + ``` + + On your macOS, you might need to add `sudo` ahead of the command. + +- Use Apache HTTP server benchmarking tool `ab` to access the application. + + ``` + $ ab -n 10000 -c 200 http://127.0.0.1/ + This is ApacheBench, Version 2.3 <$Revision: 1843412 $> + Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ + Licensed to The Apache Software Foundation, http://www.apache.org/ + + Benchmarking 127.0.0.1 (be patient) + Completed 1000 requests + ``` + + Monitor the replicas of the workload, and its replicas gradually increase from one to four. + ``` + $ vela status helloworld --svc frontend + About: + + Name: helloworld + Namespace: default + Created at: 2020-11-05 20:07:21.830118 +0800 CST + Updated at: 2020-11-05 20:50:42.664725 +0800 CST + + Services: + + - Name: frontend + Type: webservice + HEALTHY Ready: 1/1 + Traits: + - ✅ autoscale: type: cpu minReplicas: 1 maxReplicas: 5 CPUUtilization(target/current): 5%/10% replicas: 2 + Last Deployment: + Created at: 2020-11-05 20:07:23 +0800 CST + Updated at: 2020-11-05T20:50:42+08:00 + ``` + + ``` + $ vela status helloworld --svc frontend + About: + + Name: helloworld + Namespace: default + Created at: 2020-11-05 20:07:21.830118 +0800 CST + Updated at: 2020-11-05 20:50:42.664725 +0800 CST + + Services: + + - Name: frontend + Type: webservice + HEALTHY Ready: 1/1 + Traits: + - ✅ autoscale: type: cpu minReplicas: 1 maxReplicas: 5 CPUUtilization(target/current): 5%/14% replicas: 4 + Last Deployment: + Created at: 2020-11-05 20:07:23 +0800 CST + Updated at: 2020-11-05T20:50:42+08:00 + ``` + + Stop `ab` tool, and the replicas will decrease to one eventually. + + +## Scale workload by cron +Introduce how to automatically scale workloads by cron in Appfile. + +- Prepare Appfile + Follow the instructions of [appfile](./devex/appfile.md) to prepare the `vela.yaml` as below. + ``` + name: testapp + + services: + express-server: + # this image will be used in both build and deploy steps + image: zzxwill/kubevela-appfile-demo:v1 + + build: + # Here more runtime specific build templates will be supported, like NodeJS, Go, Python, Ruby. + docker: + file: Dockerfile + context: . + + cmd: ["node", "server.js"] + port: 8080 + + autoscale: + minReplicas: 1 + maxReplicas: 4 + cron: + startAt: "14:00" + duration: "2h" + days: "Monday, Thursday" + replicas: "2" + timezone: "America/Seattle" + ``` + +- Deploy an application + Run the following command to deploy the application defined in `vela.yaml`. + + ``` + $ vela up + Parsing vela.yaml ... + Loading templates ... + + Building service (express-server)... + #2 [internal] load build definition from Dockerfile + #2 sha256:c25a03ff9861be1da16a316055d11b83778efa23c655d0e69a902487bbf3c303 + #2 transferring dockerfile: 37B 0.0s done + #2 DONE 0.1s + + ... + + pushing image (zzxwill/kubevela-appfile-demo:v1)... + The push refers to repository [docker.io/zzxwill/kubevela-appfile-demo] + 1893e9ad9204: Preparing + b60a6f0fd043: Preparing + ... + 89ae5c4ee501: Layer already exists + b60a6f0fd043: Layer already exists + 1893e9ad9204: Pushed + v1: digest: sha256:11e48ce2205a1d92c1c920b3a3f41d3ee357fa2794261dc0d0e8010068e68da6 size: 1365 + + + Rendering configs for service (express-server)... + Writing deploy config to (.vela/deploy.yaml) + + Applying deploy configs ... + Checking if app has been deployed... + App has not been deployed, creating a new deployment... + ✅ App has been deployed 🚀🚀🚀 + Port forward: vela port-forward testapp + SSH: vela exec testapp + Logging: vela logs testapp + App status: vela status testapp + Service status: vela status testapp --svc express-server + ``` + +- Check the replicas and wait for the scaling to take effect + + Check the replicas of the application, there is one replica. + + ``` + $ vela status testapp + About: + + Name: testapp + Namespace: default + Created at: 2020-11-05 17:09:02.426632 +0800 CST + Updated at: 2020-11-05 17:09:02.426632 +0800 CST + + Services: + + - Name: express-server + Type: webservice + HEALTHY Ready: 1/1 + Traits: + - ✅ autoscale: type: cron minReplicas: 1 maxReplicas: 4 replicas: 1 + Last Deployment: + Created at: 2020-11-05 17:09:03 +0800 CST + Updated at: 2020-11-05T17:09:02+08:00 + ``` + + Wait till the time clocks `startAt`, and check again. The replicas become to two, which is specified as + `replicas` in `vela.yaml`. + + ``` + $ vela status testapp + About: + + Name: testapp + Namespace: default + Created at: 2020-11-05 17:09:02.426632 +0800 CST + Updated at: 2020-11-05 17:09:02.426632 +0800 CST + + Services: + + - Name: express-server + Type: webservice + HEALTHY Ready: 1/1 + Traits: + - ✅ autoscale: type: cron minReplicas: 1 maxReplicas: 4 replicas: 2 + Last Deployment: + Created at: 2020-11-05 17:09:03 +0800 CST + Updated at: 2020-11-05T17:09:02+08:00 ``` Wait after the period ends, the replicas will be one eventually. - diff --git a/e2e/commonContext.go b/e2e/commonContext.go index 4676bce34..b33c608f6 100644 --- a/e2e/commonContext.go +++ b/e2e/commonContext.go @@ -307,6 +307,10 @@ var ( q: "specify port for container ", a: "8080", }, + { + q: "CPU core requests for the workload ", + a: "", + }, } for _, qa := range data { _, err := c.ExpectString(qa.q) diff --git a/examples/testapp/vela.yaml b/examples/testapp/vela.yaml index 557709ffd..7c808f43d 100644 --- a/examples/testapp/vela.yaml +++ b/examples/testapp/vela.yaml @@ -36,6 +36,16 @@ services: # scheme: "http" # enabled: true +# autoscale: +# minReplicas: 1 +# maxReplicas: 4 +# cron: +# startAt: "14:00" +# duration: "2h" +# days: "Monday, Thursday" +# replicas: "2" +# timezone: "America/Seattle" + # pi: # image: perl # cmd: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] diff --git a/hack/vela-templates/cue/autoscale.cue b/hack/vela-templates/cue/autoscale.cue index 625a715f7..01c33cca1 100644 --- a/hack/vela-templates/cue/autoscale.cue +++ b/hack/vela-templates/cue/autoscale.cue @@ -2,29 +2,52 @@ output: { apiVersion: "standard.oam.dev/v1alpha1" kind: "Autoscaler" spec: { - minReplicas: parameter.minReplicas - maxReplicas: parameter.maxReplicas - triggers: [{ - name: parameter.name - type: parameter.type - condition: { - startAt: parameter.startAt - duration: parameter.duration - days: parameter.days - replicas: parameter.replicas - timezone: parameter.timezone - } - }, ...] + minReplicas: parameter.min + maxReplicas: parameter.max + if parameter["cpu"] != _|_ && parameter["cron"] != _|_ { + triggers: [cpuScaler, cronScaler] + } + if parameter["cpu"] != _|_ && parameter["cron"] == _|_ { + triggers: [cpuScaler] + } + if parameter["cpu"] == _|_ && parameter["cron"] != _|_ { + triggers: [cronScaler] + } } } + +cpuScaler: { + type: "cpu" + condition: { + type: "Utilization" + if parameter["cpu"] != _|_ { + value: parameter.cpu + } + } +} + +cronScaler: { + type: "cron" + if parameter["cron"] != _|_ { + condition: parameter.cron + } +} + parameter: { - minReplicas: *1 | int - maxReplicas: *4 | int - name: *"" | string - type: *"cron" | string - startAt: string - duration: string - days: string - replicas: *"2" | string - timezone: *"Asia/Shanghai" | string + // +usage=minimal replicas of the workload + min: int + // +usage=maximal replicas of the workload + max: int + // +usage=specify the value for CPU utilization, like 80, which means 80% + cpu?: string + // +usage=just for `appfile`, not available for Cli usage + cron?: { + startAt: string + duration: string + // +usage=several workdays or weekends, like "Monday, Tuesday" + days: string + replicas: string + // +usage=timezone, like "America/Seattle" + timezone: string + } } diff --git a/hack/vela-templates/cue/webservice.cue b/hack/vela-templates/cue/webservice.cue index b04d576da..66113e420 100644 --- a/hack/vela-templates/cue/webservice.cue +++ b/hack/vela-templates/cue/webservice.cue @@ -36,8 +36,17 @@ output: { ports: [{ containerPort: parameter.port }] + + if parameter["cpuRequests"] != _|_ { + resources: { + limits: + cpu: parameter.cpuRequests + requests: + cpu: parameter.cpuRequests + } + } }] - } + } } } } @@ -62,4 +71,7 @@ parameter: { } } }] + // +usage=CPU core requests for the workload + // +alias=cpu-requests + cpuRequests?: string } diff --git a/hack/vela-templates/definitions/autoscale.yaml b/hack/vela-templates/definitions/autoscale.yaml index 4ae0ca7c4..c4b1a058b 100644 --- a/hack/vela-templates/definitions/autoscale.yaml +++ b/hack/vela-templates/definitions/autoscale.yaml @@ -5,7 +5,7 @@ metadata: annotations: definition.oam.dev/apiVersion: standard.oam.dev/v1alpha1 definition.oam.dev/kind: Autoscaler - definition.oam.dev/description: "Automatically scale workloads by cron or resource utilization" + definition.oam.dev/description: "Automatically scale workloads" spec: appliesToWorkloads: - webservice @@ -16,4 +16,4 @@ spec: definitionRef: name: autoscalers.standard.oam.dev extension: - template: | \ No newline at end of file + template: | diff --git a/pkg/controller/v1alpha1/autoscaler/types.go b/pkg/controller/v1alpha1/autoscaler/types.go index 4361ca343..526e1a0d4 100644 --- a/pkg/controller/v1alpha1/autoscaler/types.go +++ b/pkg/controller/v1alpha1/autoscaler/types.go @@ -6,4 +6,5 @@ import ( const ( CronType v1alpha1.TriggerType = "cron" + CPUType v1alpha1.TriggerType = "cpu" ) diff --git a/pkg/cue/convert.go b/pkg/cue/convert.go index 80422952c..7a0661ce7 100644 --- a/pkg/cue/convert.go +++ b/pkg/cue/convert.go @@ -9,9 +9,8 @@ import ( "cuelang.org/go/cue" cueJson "cuelang.org/go/pkg/encoding/json" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "github.com/oam-dev/kubevela/api/types" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) // OutputFieldName is the name of the struct contains the CR data @@ -96,6 +95,7 @@ func GetParameters(templatePath string) ([]types.Parameter, error) { continue } var param = types.Parameter{ + Name: fi.Name, Required: !fi.IsOptional, } @@ -109,7 +109,8 @@ func GetParameters(templatePath string) ([]types.Parameter, error) { if param.Default == nil { param.Default = getDefaultByKind(param.Type) } - param.Short, param.Usage = RetrieveComments(val) + param.Short, param.Usage, param.Alias = RetrieveComments(val) + params = append(params, param) } return params, nil @@ -159,10 +160,12 @@ func GetDefault(val cue.Value) interface{} { const ( UsagePrefix = "+usage=" ShortPrefix = "+short=" + // AliasPrefix is an alias of the name of a parameter element, in order to making it more friendly to Cli users + AliasPrefix = "+alias=" ) -func RetrieveComments(value cue.Value) (string, string) { - var short, usage string +func RetrieveComments(value cue.Value) (string, string, string) { + var short, usage, alias string docs := value.Doc() for _, doc := range docs { lines := strings.Split(doc.Text(), "\n") @@ -176,7 +179,10 @@ func RetrieveComments(value cue.Value) (string, string) { if strings.HasPrefix(line, UsagePrefix) { usage = strings.TrimPrefix(line, UsagePrefix) } + if strings.HasPrefix(line, AliasPrefix) { + alias = strings.TrimPrefix(line, AliasPrefix) + } } } - return short, usage + return short, usage, alias } diff --git a/pkg/oam/trait_checker.go b/pkg/oam/trait_checker.go index 45687fa17..18c03ff71 100644 --- a/pkg/oam/trait_checker.go +++ b/pkg/oam/trait_checker.go @@ -5,18 +5,16 @@ import ( "encoding/json" "fmt" - "k8s.io/api/networking/v1beta1" - - v1 "k8s.io/api/core/v1" - - "github.com/oam-dev/kubevela/api/v1alpha1" - - "github.com/crossplane/oam-kubernetes-runtime/pkg/oam" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - runtimev1alpha1 "github.com/crossplane/crossplane-runtime/apis/core/v1alpha1" "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" + "github.com/crossplane/oam-kubernetes-runtime/pkg/oam" + "github.com/oam-dev/kubevela/api/v1alpha1" "github.com/oam-dev/kubevela/pkg/application" + autoscalers "github.com/oam-dev/kubevela/pkg/controller/v1alpha1/autoscaler" + v12 "k8s.io/api/autoscaling/v1" + v1 "k8s.io/api/core/v1" + "k8s.io/api/networking/v1beta1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -33,7 +31,12 @@ func GetChecker(traitType string, c client.Client) Checker { return &RouteChecker{c: c} case "metric": return &MetricChecker{c: c} + case "autoscale": + return &AutoscalerChecker{c: c} + case "cronscale": + return &AutoscalerChecker{c: c} } + return &DefaultChecker{c: c} } @@ -132,6 +135,43 @@ func (d *RouteChecker) Check(ctx context.Context, reference runtimev1alpha1.Type return StatusDone, message, nil } +type AutoscalerChecker struct { + c client.Client +} + +func (d *AutoscalerChecker) Check(ctx context.Context, ref runtimev1alpha1.TypedReference, _ string, appConfig *v1alpha2.ApplicationConfiguration, _ *application.Application) (CheckStatus, string, error) { + traitName := ref.Name + var scaler v1alpha1.Autoscaler + if err := d.c.Get(ctx, client.ObjectKey{Namespace: appConfig.Namespace, Name: traitName}, &scaler); err != nil { + return StatusChecking, "", err + } + var scalerType string + triggers := scaler.Spec.Triggers + if len(triggers) >= 1 { + scalerType = string(triggers[0].Type) + } + + hpaName := "keda-hpa-" + traitName + var hpa v12.HorizontalPodAutoscaler + if err := d.c.Get(ctx, client.ObjectKey{Namespace: appConfig.Namespace, Name: hpaName}, &hpa); err != nil { + return StatusChecking, "", err + } + message := fmt.Sprintf("type: %s\tminReplicas: %v\tmaxReplicas: %v\t", scalerType, *hpa.Spec.MinReplicas, + hpa.Spec.MaxReplicas) + if scalerType == string(autoscalers.CPUType) { + // When attaching trait, and before the scaler trait works, `CurrentCPUUtilizationPercentage` is nil + currentCPUUtilizationPercentage := hpa.Status.CurrentCPUUtilizationPercentage + var zeroPercentage int32 = 0 + if currentCPUUtilizationPercentage == nil { + currentCPUUtilizationPercentage = &zeroPercentage + } + message += fmt.Sprintf("CPUUtilization(target/current): %v%%/%v%%\t", *hpa.Spec.TargetCPUUtilizationPercentage, + *currentCPUUtilizationPercentage) + } + message += fmt.Sprintf("replicas: %v", hpa.Status.CurrentReplicas) + return StatusDone, message, nil +} + func GetUnstructured(ctx context.Context, c client.Client, ns string, resourceRef runtimev1alpha1.TypedReference) (*unstructured.Unstructured, error) { resource := unstructured.Unstructured{} resource.SetGroupVersionKind(resourceRef.GroupVersionKind()) diff --git a/pkg/oam/workload.go b/pkg/oam/workload.go index 1d8779d7b..04c991e0e 100644 --- a/pkg/oam/workload.go +++ b/pkg/oam/workload.go @@ -6,13 +6,12 @@ import ( "strconv" "strings" + "cuelang.org/go/cue" "github.com/oam-dev/kubevela/api/types" "github.com/oam-dev/kubevela/pkg/application" "github.com/oam-dev/kubevela/pkg/commands/util" cmdutil "github.com/oam-dev/kubevela/pkg/commands/util" "github.com/oam-dev/kubevela/pkg/plugins" - - "cuelang.org/go/cue" "github.com/spf13/pflag" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -62,30 +61,35 @@ func BaseComplete(envName string, workloadName string, appName string, flagSet * } for _, v := range template.Parameters { + name := v.Name + if v.Alias != "" { + name = v.Alias + } // Cli can check required flag before make a request to backend, but API itself could not, so validate flags here - flag := flagSet.Lookup(v.Name) - if v.Name == "name" { + flag := flagSet.Lookup(name) + if name == "name" { continue } if flag == nil || flag.Value.String() == "" { if v.Required { - return nil, fmt.Errorf("required flag(s) \"%s\" not set", v.Name) + return nil, fmt.Errorf("required flag(s) \"%s\" not set", name) } continue } + switch v.Type { case cue.IntKind: - workloadData[v.Name], err = flagSet.GetInt64(v.Name) + workloadData[v.Name], err = flagSet.GetInt64(name) case cue.StringKind: - workloadData[v.Name], err = flagSet.GetString(v.Name) + workloadData[v.Name], err = flagSet.GetString(name) case cue.BoolKind: - workloadData[v.Name], err = flagSet.GetBool(v.Name) + workloadData[v.Name], err = flagSet.GetBool(name) case cue.NumberKind, cue.FloatKind: - workloadData[v.Name], err = flagSet.GetFloat64(v.Name) + workloadData[v.Name], err = flagSet.GetFloat64(name) } if err != nil { if strings.Contains(err.Error(), "of flag of type string") { - data, _ := flagSet.GetString(v.Name) + data, _ := flagSet.GetString(name) switch v.Type { case cue.IntKind: workloadData[v.Name], err = strconv.ParseInt(data, 10, 64)