forked from LaconicNetwork/kompose
added this labels:
kompose.hpa.minreplicas kompose.hpa.maxreplicas kompose.hpa.cpu kompose.hpa.memory documentated labels user_guide.md generate custom metrics from cpu, memory and set min/max replicas Signed-off-by: jose luis <2064537+sosan@users.noreply.github.com>
This commit is contained in:
parent
14152d4a81
commit
a38f7f9ea3
@ -211,6 +211,10 @@ The currently supported options are:
|
||||
| kompose.cronjob.schedule | kubernetes cronjob schedule (for example: '1 * * * *') |
|
||||
| kompose.cronjob.concurrency_policy | 'Forbid' / 'Allow' / 'Never' / '' |
|
||||
| kompose.cronjob.backoff_limit | kubernetes cronjob backoff limit (for example: '6') |
|
||||
| kompose.hpa.minreplicas | defines Horizontal Pod Autoscaler min pod replicas |
|
||||
| kompose.hpa.maxreplicas | defines Horizontal Pod Autoscaler max pod replicas |
|
||||
| kompose.hpa.cpu | defines Horizontal Pod Autoscaler cpu utilization trigger |
|
||||
| kompose.hpa.memory | defines Horizontal Pod Autoscaler memory utilization trigger |
|
||||
|
||||
**Note**: `kompose.service.type` label should be defined with `ports` only (except for headless service), otherwise `kompose` will fail.
|
||||
|
||||
@ -467,6 +471,63 @@ services:
|
||||
labels:
|
||||
kompose.volume.sub-path: pg-data
|
||||
```
|
||||
|
||||
- `kompose.hpa.minreplicas` defines minimum replicas from Horizontal Pod Autoscaler. Default value 1 [HPA Min Replicas](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-multiple-metrics-and-custom-metrics).
|
||||
|
||||
For example:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
pgadmin:
|
||||
image: postgres
|
||||
labels:
|
||||
kompose.hpa.minreplicas: 1
|
||||
```
|
||||
|
||||
- `kompose.hpa.maxreplicas` defines maximum replicas from Horizontal Pod Autoscaler. Default value 10 [HPA Max Replicas](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-multiple-metrics-and-custom-metrics).
|
||||
|
||||
For example:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
pgadmin:
|
||||
image: postgres
|
||||
labels:
|
||||
kompose.hpa.maxreplicas: 10
|
||||
```
|
||||
|
||||
- `kompose.hpa.cpu` defines % cpu utilization trigger scale from Horizontal Pod Autoscaler. It is represented as a percentage of a resource. Default value: 50 [HPA CPU Utilization](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-multiple-metrics-and-custom-metrics).
|
||||
|
||||
For example:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
pgadmin:
|
||||
image: postgres
|
||||
labels:
|
||||
kompose.hpa.cpu: 50
|
||||
```
|
||||
|
||||
- `kompose.hpa.memory` defines memory utilization trigger scale from Horizontal Pod Autoscaler. It is represented as a percentage of a resource. Default value: 70 [HPA Memory Utilization](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-multiple-metrics-and-custom-metrics).
|
||||
|
||||
For example:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
pgadmin:
|
||||
image: postgres
|
||||
labels:
|
||||
kompose.hpa.memory: 50
|
||||
```
|
||||
|
||||
## Restart
|
||||
|
||||
If you want to create normal pods without controller you can use `restart` construct of compose to define that. Follow table below to see what happens on the `restart` value.
|
||||
|
||||
@ -87,6 +87,14 @@ const (
|
||||
LabelCronJobConcurrencyPolicy = "kompose.cronjob.concurrency_policy"
|
||||
// LabelCronJobBackoffLimit defines the job backoff limit
|
||||
LabelCronJobBackoffLimit = "kompose.cronjob.backoff_limit"
|
||||
// LabelHpaMinReplicas defines min pod replicas
|
||||
LabelHpaMinReplicas = "kompose.hpa.minreplicas"
|
||||
// LabelHpaMaxReplicas defines max pod replicas
|
||||
LabelHpaMaxReplicas = "kompose.hpa.maxreplicas"
|
||||
// LabelHpaCpu defines scaling decisions based on CPU utilization
|
||||
LabelHpaCPU = "kompose.hpa.cpu"
|
||||
// LabelHpaMemory defines scaling decisions based on memory utilization
|
||||
LabelHpaMemory = "kompose.hpa.memory"
|
||||
)
|
||||
|
||||
// load environment variables from compose file
|
||||
|
||||
@ -41,6 +41,7 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v3"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
hpa "k8s.io/api/autoscaling/v2beta2"
|
||||
api "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@ -48,6 +49,29 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Default values for Horizontal Pod Autoscaler (HPA)
|
||||
const (
|
||||
DefaultMinReplicas = 1
|
||||
DefaultMaxReplicas = 10
|
||||
DefaultCpuUtilization = 50
|
||||
DefaultMemoryUtilization = 70
|
||||
)
|
||||
|
||||
// LabelKeys are the keys for HPA related labels in the service
|
||||
var LabelKeys = []string{
|
||||
compose.LabelHpaCPU,
|
||||
compose.LabelHpaMemory,
|
||||
compose.LabelHpaMinReplicas,
|
||||
compose.LabelHpaMaxReplicas,
|
||||
}
|
||||
|
||||
type HpaValues struct {
|
||||
MinReplicas int32
|
||||
MaxReplicas int32
|
||||
CPUtilization int32
|
||||
MemoryUtilization int32
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Helm Chart configuration
|
||||
*/
|
||||
@ -985,3 +1009,107 @@ func reformatSecretConfigUnderscoreWithDash(secretConfig types.ServiceSecretConf
|
||||
|
||||
return newSecretConfig
|
||||
}
|
||||
|
||||
// searchHPAValues is useful to check if labels
|
||||
// contains any labels related to Horizontal Pod Autoscaler
|
||||
func searchHPAValues(labels map[string]string) bool {
|
||||
found := true
|
||||
for _, value := range LabelKeys {
|
||||
if _, ok := labels[value]; ok {
|
||||
return found
|
||||
}
|
||||
}
|
||||
return !found
|
||||
}
|
||||
|
||||
// createHPAResources creates a HorizontalPodAutoscaler (HPA) resource
|
||||
// It sets the number of replicas in the service to 0 because
|
||||
// the number of replicas will be managed by the HPA
|
||||
func createHPAResources(name string, service *kobject.ServiceConfig) hpa.HorizontalPodAutoscaler {
|
||||
valuesHpa := getResourceHpaValues(service)
|
||||
service.Replicas = 0
|
||||
metrics := getHpaMetricSpec(valuesHpa)
|
||||
scalerSpecs := hpa.HorizontalPodAutoscaler{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "HorizontalPodAutoscaler",
|
||||
APIVersion: "autoscaling/v2",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
Spec: hpa.HorizontalPodAutoscalerSpec{
|
||||
ScaleTargetRef: hpa.CrossVersionObjectReference{
|
||||
Kind: "Deployment",
|
||||
Name: name,
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
MinReplicas: &valuesHpa.MinReplicas,
|
||||
MaxReplicas: valuesHpa.MaxReplicas,
|
||||
Metrics: metrics,
|
||||
},
|
||||
}
|
||||
|
||||
return scalerSpecs
|
||||
}
|
||||
|
||||
// getResourceHpaValues retrieves the min/max replicas and CPU/memory utilization values
|
||||
// control if maxReplicas is less than minReplicas
|
||||
func getResourceHpaValues(service *kobject.ServiceConfig) HpaValues {
|
||||
minReplicas := getHpaValue(service, compose.LabelHpaMinReplicas, DefaultMinReplicas)
|
||||
maxReplicas := getHpaValue(service, compose.LabelHpaMaxReplicas, DefaultMaxReplicas)
|
||||
|
||||
if maxReplicas < minReplicas {
|
||||
maxReplicas = minReplicas
|
||||
}
|
||||
|
||||
return HpaValues{
|
||||
MinReplicas: minReplicas,
|
||||
MaxReplicas: maxReplicas,
|
||||
CPUtilization: getHpaValue(service, compose.LabelHpaCPU, DefaultCpuUtilization),
|
||||
MemoryUtilization: getHpaValue(service, compose.LabelHpaMemory, DefaultMemoryUtilization),
|
||||
}
|
||||
}
|
||||
|
||||
// getHpaValue convert the label value to integer
|
||||
// If the label is not present or the conversion fails
|
||||
// it returns the provided default value
|
||||
func getHpaValue(service *kobject.ServiceConfig, label string, defaultValue int32) int32 {
|
||||
valueFromLabel, err := strconv.Atoi(service.Labels[label])
|
||||
if err != nil || valueFromLabel <= 0 {
|
||||
return defaultValue
|
||||
}
|
||||
return int32(valueFromLabel)
|
||||
}
|
||||
|
||||
// getHpaMetricSpec returns a list of metric specs for the HPA resource
|
||||
// Target type is hardcoded to hpa.UtilizationMetricType
|
||||
// Each MetricSpec specifies the type metric CPU/memory and average utilization value
|
||||
// to trigger scaling
|
||||
func getHpaMetricSpec(hpaValues HpaValues) []hpa.MetricSpec {
|
||||
var metrics []hpa.MetricSpec
|
||||
if hpaValues.CPUtilization > 0 {
|
||||
metrics = append(metrics, hpa.MetricSpec{
|
||||
Type: hpa.ResourceMetricSourceType,
|
||||
Resource: &hpa.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
Target: hpa.MetricTarget{
|
||||
Type: hpa.UtilizationMetricType,
|
||||
AverageUtilization: &hpaValues.CPUtilization,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
if hpaValues.MemoryUtilization > 0 {
|
||||
metrics = append(metrics, hpa.MetricSpec{
|
||||
Type: hpa.ResourceMetricSourceType,
|
||||
Resource: &hpa.ResourceMetricSource{
|
||||
Name: api.ResourceMemory,
|
||||
Target: hpa.MetricTarget{
|
||||
Type: hpa.UtilizationMetricType,
|
||||
AverageUtilization: &hpaValues.MemoryUtilization,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
return metrics
|
||||
}
|
||||
|
||||
@ -29,7 +29,9 @@ import (
|
||||
"github.com/kubernetes/kompose/pkg/testutils"
|
||||
"github.com/pkg/errors"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
hpa "k8s.io/api/autoscaling/v2beta2"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
/*
|
||||
@ -738,3 +740,579 @@ func TestRemoveEmptyInterfaces(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getHpaValue(t *testing.T) {
|
||||
type args struct {
|
||||
service *kobject.ServiceConfig
|
||||
label string
|
||||
defaultValue int32
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want int32
|
||||
}{
|
||||
// LabelHpaMinReplicas
|
||||
{
|
||||
name: "LabelHpaMinReplicas with 1 value",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "1",
|
||||
compose.LabelHpaMaxReplicas: "10",
|
||||
compose.LabelHpaCPU: "50",
|
||||
compose.LabelHpaMemory: "70",
|
||||
},
|
||||
},
|
||||
label: compose.LabelHpaMinReplicas,
|
||||
defaultValue: 1,
|
||||
},
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "LabelHpaMinReplicas with 0 value",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "0",
|
||||
compose.LabelHpaMaxReplicas: "10",
|
||||
compose.LabelHpaCPU: "50",
|
||||
compose.LabelHpaMemory: "70",
|
||||
},
|
||||
},
|
||||
label: compose.LabelHpaMinReplicas,
|
||||
defaultValue: 1,
|
||||
},
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "LabelHpaMinReplicas with error value",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "cannot transform",
|
||||
compose.LabelHpaMaxReplicas: "10",
|
||||
compose.LabelHpaCPU: "50",
|
||||
compose.LabelHpaMemory: "70",
|
||||
},
|
||||
},
|
||||
label: compose.LabelHpaMinReplicas,
|
||||
defaultValue: 1,
|
||||
},
|
||||
want: 1,
|
||||
},
|
||||
// LabelHpaMaxReplicas
|
||||
{
|
||||
name: "LabelHpaMaxReplicas with 10 value",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "1",
|
||||
compose.LabelHpaMaxReplicas: "10",
|
||||
compose.LabelHpaCPU: "50",
|
||||
compose.LabelHpaMemory: "70",
|
||||
},
|
||||
},
|
||||
label: compose.LabelHpaMaxReplicas,
|
||||
defaultValue: 30,
|
||||
},
|
||||
want: 10,
|
||||
},
|
||||
{
|
||||
name: "LabelHpaMaxReplicas with 0 value",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "1",
|
||||
compose.LabelHpaMaxReplicas: "0",
|
||||
compose.LabelHpaCPU: "50",
|
||||
compose.LabelHpaMemory: "70",
|
||||
},
|
||||
},
|
||||
label: compose.LabelHpaMaxReplicas,
|
||||
defaultValue: 10,
|
||||
},
|
||||
want: 10,
|
||||
},
|
||||
{
|
||||
name: "LabelHpaMaxReplicas with error value",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "1",
|
||||
compose.LabelHpaMaxReplicas: "cannot transform",
|
||||
compose.LabelHpaCPU: "50",
|
||||
compose.LabelHpaMemory: "70",
|
||||
},
|
||||
},
|
||||
label: compose.LabelHpaMaxReplicas,
|
||||
defaultValue: 10,
|
||||
},
|
||||
want: 10,
|
||||
},
|
||||
// LabelHpaCPU
|
||||
{
|
||||
name: "LabelHpaCPU with 50 value",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "1",
|
||||
compose.LabelHpaMaxReplicas: "10",
|
||||
compose.LabelHpaCPU: "50",
|
||||
compose.LabelHpaMemory: "70",
|
||||
},
|
||||
},
|
||||
label: compose.LabelHpaCPU,
|
||||
defaultValue: 30,
|
||||
},
|
||||
want: 50,
|
||||
},
|
||||
{
|
||||
name: "LabelHpaCPU with 0 value",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "1",
|
||||
compose.LabelHpaMaxReplicas: "10",
|
||||
compose.LabelHpaCPU: "0",
|
||||
compose.LabelHpaMemory: "70",
|
||||
},
|
||||
},
|
||||
label: compose.LabelHpaCPU,
|
||||
defaultValue: 50,
|
||||
},
|
||||
want: 50,
|
||||
},
|
||||
{
|
||||
name: "LabelHpaCPU with error value",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "1",
|
||||
compose.LabelHpaMaxReplicas: "10",
|
||||
compose.LabelHpaCPU: "cannot transform",
|
||||
compose.LabelHpaMemory: "70",
|
||||
},
|
||||
},
|
||||
label: compose.LabelHpaCPU,
|
||||
defaultValue: 50,
|
||||
},
|
||||
want: 50,
|
||||
},
|
||||
// LabelHpaMemory
|
||||
{
|
||||
name: "LabelHpaMemory with 70 value",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "1",
|
||||
compose.LabelHpaMaxReplicas: "10",
|
||||
compose.LabelHpaCPU: "50",
|
||||
compose.LabelHpaMemory: "70",
|
||||
},
|
||||
},
|
||||
label: compose.LabelHpaMemory,
|
||||
defaultValue: 30,
|
||||
},
|
||||
want: 70,
|
||||
},
|
||||
{
|
||||
name: "LabelHpaMemory with 0 value",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "1",
|
||||
compose.LabelHpaMaxReplicas: "10",
|
||||
compose.LabelHpaCPU: "50",
|
||||
compose.LabelHpaMemory: "0",
|
||||
},
|
||||
},
|
||||
label: compose.LabelHpaMemory,
|
||||
defaultValue: 70,
|
||||
},
|
||||
want: 70,
|
||||
},
|
||||
{
|
||||
name: "LabelHpaMemory with error value",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "1",
|
||||
compose.LabelHpaMaxReplicas: "10",
|
||||
compose.LabelHpaCPU: "50",
|
||||
compose.LabelHpaMemory: "cannot transform",
|
||||
},
|
||||
},
|
||||
label: compose.LabelHpaMemory,
|
||||
defaultValue: 70,
|
||||
},
|
||||
want: 70,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := getHpaValue(tt.args.service, tt.args.label, tt.args.defaultValue); got != tt.want {
|
||||
t.Errorf("getHpaValue() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getResourceHpaValues(t *testing.T) {
|
||||
type args struct {
|
||||
service *kobject.ServiceConfig
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want HpaValues
|
||||
}{
|
||||
{
|
||||
name: "check same values",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "1",
|
||||
compose.LabelHpaMaxReplicas: "10",
|
||||
compose.LabelHpaCPU: "50",
|
||||
compose.LabelHpaMemory: "70",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: HpaValues{
|
||||
MinReplicas: 1,
|
||||
MaxReplicas: 10,
|
||||
CPUtilization: 50,
|
||||
MemoryUtilization: 70,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "check same values",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "5",
|
||||
compose.LabelHpaMaxReplicas: "3",
|
||||
compose.LabelHpaCPU: "50",
|
||||
compose.LabelHpaMemory: "70",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: HpaValues{
|
||||
MinReplicas: 5,
|
||||
MaxReplicas: 5,
|
||||
CPUtilization: 50,
|
||||
MemoryUtilization: 70,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with error values and use default values from LabelHpaMinReplicas",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "cannot transform",
|
||||
compose.LabelHpaMaxReplicas: "3",
|
||||
compose.LabelHpaCPU: "50",
|
||||
compose.LabelHpaMemory: "70",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: HpaValues{
|
||||
MinReplicas: 1,
|
||||
MaxReplicas: 3,
|
||||
CPUtilization: 50,
|
||||
MemoryUtilization: 70,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "LabelHpaMaxReplicas is minor to LabelHpaMinReplicas",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "6",
|
||||
compose.LabelHpaMaxReplicas: "5",
|
||||
compose.LabelHpaCPU: "50",
|
||||
compose.LabelHpaMemory: "70",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: HpaValues{
|
||||
MinReplicas: 6,
|
||||
MaxReplicas: 6,
|
||||
CPUtilization: 50,
|
||||
MemoryUtilization: 70,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "error label and LabelHpaMaxReplicas is minor to LabelHpaMinReplicas",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "6",
|
||||
compose.LabelHpaMaxReplicas: "5",
|
||||
compose.LabelHpaCPU: "cannot transform",
|
||||
compose.LabelHpaMemory: "70",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: HpaValues{
|
||||
MinReplicas: 6,
|
||||
MaxReplicas: 6,
|
||||
CPUtilization: 50,
|
||||
MemoryUtilization: 70,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "error label and LabelHpaMaxReplicas is minor to LabelHpaMinReplicas",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "6",
|
||||
compose.LabelHpaMaxReplicas: "5",
|
||||
compose.LabelHpaCPU: "50",
|
||||
compose.LabelHpaMemory: "cannot transform",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: HpaValues{
|
||||
MinReplicas: 6,
|
||||
MaxReplicas: 6,
|
||||
CPUtilization: 50,
|
||||
MemoryUtilization: 70,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "all error label",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "cannot transform",
|
||||
compose.LabelHpaMaxReplicas: "cannot transform",
|
||||
compose.LabelHpaCPU: "cannot transform",
|
||||
compose.LabelHpaMemory: "cannot transform",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: HpaValues{
|
||||
MinReplicas: 1,
|
||||
MaxReplicas: 10,
|
||||
CPUtilization: 50,
|
||||
MemoryUtilization: 70,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "error label without some labels",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "cannot transform",
|
||||
compose.LabelHpaMaxReplicas: "cannot transform",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: HpaValues{
|
||||
MinReplicas: 1,
|
||||
MaxReplicas: 10,
|
||||
CPUtilization: 50,
|
||||
MemoryUtilization: 70,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "without labels, should return default values",
|
||||
args: args{
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{},
|
||||
},
|
||||
},
|
||||
want: HpaValues{
|
||||
MinReplicas: 1,
|
||||
MaxReplicas: 10,
|
||||
CPUtilization: 50,
|
||||
MemoryUtilization: 70,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := getResourceHpaValues(tt.args.service); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("getResourceHpaValues() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getHpaMetricSpec(t *testing.T) {
|
||||
valueCPUFixed := int32(50)
|
||||
valueMemoryFixed := int32(70)
|
||||
type args struct {
|
||||
hpaValues HpaValues
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []hpa.MetricSpec
|
||||
}{
|
||||
{
|
||||
name: "no values",
|
||||
args: args{
|
||||
hpaValues: HpaValues{},
|
||||
},
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "only cpu",
|
||||
args: args{
|
||||
hpaValues: HpaValues{
|
||||
CPUtilization: 50,
|
||||
},
|
||||
},
|
||||
want: []hpa.MetricSpec{
|
||||
{
|
||||
Type: hpa.ResourceMetricSourceType,
|
||||
Resource: &hpa.ResourceMetricSource{
|
||||
Name: "cpu",
|
||||
Target: hpa.MetricTarget{
|
||||
Type: hpa.UtilizationMetricType,
|
||||
AverageUtilization: &valueCPUFixed,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "only memory",
|
||||
args: args{
|
||||
hpaValues: HpaValues{
|
||||
MemoryUtilization: 70,
|
||||
},
|
||||
},
|
||||
want: []hpa.MetricSpec{
|
||||
{
|
||||
Type: hpa.ResourceMetricSourceType,
|
||||
Resource: &hpa.ResourceMetricSource{
|
||||
Name: "memory",
|
||||
Target: hpa.MetricTarget{
|
||||
Type: hpa.UtilizationMetricType,
|
||||
AverageUtilization: &valueMemoryFixed,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cpu and memory",
|
||||
args: args{
|
||||
hpaValues: HpaValues{
|
||||
CPUtilization: 50,
|
||||
MemoryUtilization: 70,
|
||||
},
|
||||
},
|
||||
want: []hpa.MetricSpec{
|
||||
{
|
||||
Type: hpa.ResourceMetricSourceType,
|
||||
Resource: &hpa.ResourceMetricSource{
|
||||
Name: "cpu",
|
||||
Target: hpa.MetricTarget{
|
||||
Type: hpa.UtilizationMetricType,
|
||||
AverageUtilization: &valueCPUFixed,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: hpa.ResourceMetricSourceType,
|
||||
Resource: &hpa.ResourceMetricSource{
|
||||
Name: "memory",
|
||||
Target: hpa.MetricTarget{
|
||||
Type: hpa.UtilizationMetricType,
|
||||
AverageUtilization: &valueMemoryFixed,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := getHpaMetricSpec(tt.args.hpaValues); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("getHpaMetricSpec() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_createHPAResources(t *testing.T) {
|
||||
valueCPUFixed := int32(50)
|
||||
valueMemoryFixed := int32(70)
|
||||
fixedMinReplicas := int32(1)
|
||||
type args struct {
|
||||
name string
|
||||
service *kobject.ServiceConfig
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want hpa.HorizontalPodAutoscaler
|
||||
}{
|
||||
{
|
||||
name: "all labels",
|
||||
args: args{
|
||||
name: "web",
|
||||
service: &kobject.ServiceConfig{
|
||||
Labels: map[string]string{
|
||||
compose.LabelHpaMinReplicas: "1",
|
||||
compose.LabelHpaMaxReplicas: "10",
|
||||
compose.LabelHpaCPU: "50",
|
||||
compose.LabelHpaMemory: "70",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: hpa.HorizontalPodAutoscaler{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "HorizontalPodAutoscaler",
|
||||
APIVersion: "autoscaling/v2",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "web",
|
||||
},
|
||||
Spec: hpa.HorizontalPodAutoscalerSpec{
|
||||
ScaleTargetRef: hpa.CrossVersionObjectReference{
|
||||
Kind: "Deployment",
|
||||
Name: "web",
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
MinReplicas: &fixedMinReplicas,
|
||||
MaxReplicas: 10,
|
||||
Metrics: []hpa.MetricSpec{
|
||||
{
|
||||
Type: hpa.ResourceMetricSourceType,
|
||||
Resource: &hpa.ResourceMetricSource{
|
||||
Name: "cpu",
|
||||
Target: hpa.MetricTarget{
|
||||
Type: hpa.UtilizationMetricType,
|
||||
AverageUtilization: &valueCPUFixed,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: hpa.ResourceMetricSourceType,
|
||||
Resource: &hpa.ResourceMetricSource{
|
||||
Name: "memory",
|
||||
Target: hpa.MetricTarget{
|
||||
Type: hpa.UtilizationMetricType,
|
||||
AverageUtilization: &valueMemoryFixed,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := createHPAResources(tt.args.name, tt.args.service); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("createHPAResources() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1654,6 +1654,10 @@ func (k *Kubernetes) Transform(komposeObject kobject.KomposeObject, opt kobject.
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
err = k.configHorizontalPodScaler(name, service, opt, &objects)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error transforming Kubernetes objects")
|
||||
}
|
||||
allobjects = append(allobjects, objects...)
|
||||
}
|
||||
|
||||
@ -1718,3 +1722,16 @@ func (k *Kubernetes) UpdateController(obj runtime.Object, updateTemplate func(*a
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// configHorizontalPodScaler create Hpa resource also append to the objects
|
||||
// first checks if the service labels contain any HPA labels using the searchHPAValues
|
||||
func (k *Kubernetes) configHorizontalPodScaler(name string, service kobject.ServiceConfig, opt kobject.ConvertOptions, objects *[]runtime.Object) (err error) {
|
||||
found := searchHPAValues(service.Labels)
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
|
||||
hpa := createHPAResources(name, &service)
|
||||
*objects = append(*objects, &hpa)
|
||||
return nil
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user