Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add ContainerResource type for HPA cpu/memory scaler #3513

Merged
merged 3 commits into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ To learn more about our roadmap, we recommend reading [this document](ROADMAP.md
- **General:** Use more readable timestamps in KEDA Operator logs ([#3066](https://github.com/kedacore/keda/issue/3066))
- **AWS SQS Queue Scaler:** Support for scaling to include in-flight messages. ([#3133](https://github.com/kedacore/keda/issues/3133))
- **Azure Pipelines Scaler:** Add support for Azure Pipelines to support demands (capabilities) ([#2328](https://github.com/kedacore/keda/issues/2328))
- **CPU/Memory Scaler:** Added support for targeting specific container in a pod ([#1378](https://github.com/kedacore/keda/issues/1378))
- **GCP Stackdriver Scaler:** Added aggregation parameters ([#3008](https://github.com/kedacore/keda/issues/3008))
- **Kafka Scaler:** Handle Sarama errors properly ([#3056](https://github.com/kedacore/keda/issues/3056))
- **Kafka Scaler:** Support of passphrase encrypted PKCS #\8 private key ([3449](https://github.com/kedacore/keda/issues/3449))
- **Prometheus Scaler:** Add ignoreNullValues to return error when prometheus return null in values ([#3065](https://github.com/kedacore/keda/issues/3065))
- **Selenium Grid Scaler:** Edge active sessions not being properly counted ([#2709](https://github.com/kedacore/keda/issues/2709))
- **Selenium Grid Scaler:** Max Sessions implementation issue ([#3061](https://github.com/kedacore/keda/issues/3061))
- **Selenium Grid Scaler:** Max Sessions implementation issue ([#3061](https://github.c>>>>>>> mainom/kedacore/keda/issues/3061))

### Fixes

Expand Down
38 changes: 30 additions & 8 deletions pkg/scalers/cpu_memory_scaler.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type cpuMemoryMetadata struct {
Type v2beta2.MetricTargetType
AverageValue *resource.Quantity
AverageUtilization *int32
ContainerName string
}

// NewCPUMemoryScaler creates a new cpuMemoryScaler
Expand Down Expand Up @@ -73,6 +74,11 @@ func parseResourceMetadata(config *ScalerConfig, logger logr.Logger) (*cpuMemory
default:
return nil, fmt.Errorf("unsupported metric type, allowed values are 'Utilization' or 'AverageValue'")
}

if value, ok = config.TriggerMetadata["containerName"]; ok && value != "" {
meta.ContainerName = value
}

return meta, nil
}

Expand All @@ -88,15 +94,31 @@ func (s *cpuMemoryScaler) Close(context.Context) error {

// GetMetricSpecForScaling returns the metric spec for the HPA
func (s *cpuMemoryScaler) GetMetricSpecForScaling(context.Context) []v2beta2.MetricSpec {
cpuMemoryMetric := &v2beta2.ResourceMetricSource{
Name: s.resourceName,
Target: v2beta2.MetricTarget{
Type: s.metadata.Type,
AverageUtilization: s.metadata.AverageUtilization,
AverageValue: s.metadata.AverageValue,
},
var metricSpec v2beta2.MetricSpec

if s.metadata.ContainerName != "" {
containerCPUMemoryMetric := &v2beta2.ContainerResourceMetricSource{
Name: s.resourceName,
Target: v2beta2.MetricTarget{
Type: s.metadata.Type,
AverageUtilization: s.metadata.AverageUtilization,
AverageValue: s.metadata.AverageValue,
},
Container: s.metadata.ContainerName,
}
metricSpec = v2beta2.MetricSpec{ContainerResource: containerCPUMemoryMetric, Type: v2beta2.ContainerResourceMetricSourceType}
} else {
cpuMemoryMetric := &v2beta2.ResourceMetricSource{
Name: s.resourceName,
Target: v2beta2.MetricTarget{
Type: s.metadata.Type,
AverageUtilization: s.metadata.AverageUtilization,
AverageValue: s.metadata.AverageValue,
},
}
metricSpec = v2beta2.MetricSpec{Resource: cpuMemoryMetric, Type: v2beta2.ResourceMetricSourceType}
}
metricSpec := v2beta2.MetricSpec{Resource: cpuMemoryMetric, Type: v2beta2.ResourceMetricSourceType}

return []v2beta2.MetricSpec{metricSpec}
}

Expand Down
33 changes: 33 additions & 0 deletions pkg/scalers/cpu_memory_scaler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,16 @@ var validCPUMemoryMetadata = map[string]string{
"type": "Utilization",
"value": "50",
}
var validContainerCPUMemoryMetadata = map[string]string{
"type": "Utilization",
"value": "50",
"containerName": "foo",
}

var testCPUMemoryMetadata = []parseCPUMemoryMetadataTestData{
{"", map[string]string{}, true},
{"", validCPUMemoryMetadata, false},
{"", validContainerCPUMemoryMetadata, false},
{"", map[string]string{"type": "Utilization", "value": "50"}, false},
{v2beta2.UtilizationMetricType, map[string]string{"value": "50"}, false},
{"", map[string]string{"type": "AverageValue", "value": "50"}, false},
Expand Down Expand Up @@ -75,3 +81,30 @@ func TestGetMetricSpecForScaling(t *testing.T) {
assert.Equal(t, metricSpec[0].Resource.Name, v1.ResourceCPU)
assert.Equal(t, metricSpec[0].Resource.Target.Type, v2beta2.UtilizationMetricType)
}

func TestGetContainerMetricSpecForScaling(t *testing.T) {
// Using trigger.metadata.type field for type
config := &ScalerConfig{
TriggerMetadata: validContainerCPUMemoryMetadata,
}
scaler, _ := NewCPUMemoryScaler(v1.ResourceCPU, config)
metricSpec := scaler.GetMetricSpecForScaling(context.Background())

assert.Equal(t, metricSpec[0].Type, v2beta2.ContainerResourceMetricSourceType)
assert.Equal(t, metricSpec[0].ContainerResource.Name, v1.ResourceCPU)
assert.Equal(t, metricSpec[0].ContainerResource.Target.Type, v2beta2.UtilizationMetricType)
assert.Equal(t, metricSpec[0].ContainerResource.Container, validContainerCPUMemoryMetadata["containerName"])

// Using trigger.metricType field for type
config = &ScalerConfig{
TriggerMetadata: map[string]string{"value": "50", "containerName": "bar"},
MetricType: v2beta2.UtilizationMetricType,
}
scaler, _ = NewCPUMemoryScaler(v1.ResourceCPU, config)
metricSpec = scaler.GetMetricSpecForScaling(context.Background())

assert.Equal(t, metricSpec[0].Type, v2beta2.ContainerResourceMetricSourceType)
assert.Equal(t, metricSpec[0].ContainerResource.Name, v1.ResourceCPU)
assert.Equal(t, metricSpec[0].ContainerResource.Target.Type, v2beta2.UtilizationMetricType)
assert.Equal(t, metricSpec[0].ContainerResource.Container, "bar")
}