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.schedule | kubernetes cronjob schedule (for example: '1 * * * *') |
|
||||||
| kompose.cronjob.concurrency_policy | 'Forbid' / 'Allow' / 'Never' / '' |
|
| kompose.cronjob.concurrency_policy | 'Forbid' / 'Allow' / 'Never' / '' |
|
||||||
| kompose.cronjob.backoff_limit | kubernetes cronjob backoff limit (for example: '6') |
|
| 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.
|
**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:
|
labels:
|
||||||
kompose.volume.sub-path: pg-data
|
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
|
## 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.
|
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"
|
LabelCronJobConcurrencyPolicy = "kompose.cronjob.concurrency_policy"
|
||||||
// LabelCronJobBackoffLimit defines the job backoff limit
|
// LabelCronJobBackoffLimit defines the job backoff limit
|
||||||
LabelCronJobBackoffLimit = "kompose.cronjob.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
|
// load environment variables from compose file
|
||||||
|
|||||||
@ -41,6 +41,7 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
|
hpa "k8s.io/api/autoscaling/v2beta2"
|
||||||
api "k8s.io/api/core/v1"
|
api "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@ -48,6 +49,29 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"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
|
* Generate Helm Chart configuration
|
||||||
*/
|
*/
|
||||||
@ -985,3 +1009,107 @@ func reformatSecretConfigUnderscoreWithDash(secretConfig types.ServiceSecretConf
|
|||||||
|
|
||||||
return newSecretConfig
|
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/kubernetes/kompose/pkg/testutils"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
|
hpa "k8s.io/api/autoscaling/v2beta2"
|
||||||
corev1 "k8s.io/api/core/v1"
|
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
|
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...)
|
allobjects = append(allobjects, objects...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1718,3 +1722,16 @@ func (k *Kubernetes) UpdateController(obj runtime.Object, updateTemplate func(*a
|
|||||||
}
|
}
|
||||||
return nil
|
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