Skip to content

Commit

Permalink
Postgres: optional metricName & mask passwords (#1381)
Browse files Browse the repository at this point in the history
Signed-off-by: ycabrer <[email protected]>
  • Loading branch information
ycabrer authored Dec 1, 2020
1 parent d532671 commit 9c86c7c
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 11 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
### Improvements
- Support add ScaledJob's label to its job ([#1311](https://github.com/kedacore/keda/issues/1311))
- Bug fix in aws_iam_authorization to utilize correct secret from env key name ([PR #1332](https://github.com/kedacore/keda/pull/1332))
- Add metricName field to postgres scaler and auto generate if not defined. ([PR #1381](https://github.com/kedacore/keda/pull/1381))
- Mask password in postgres scaler auto generated metricName. ([PR #1381](https://github.com/kedacore/keda/pull/1381))

### Breaking Changes

Expand Down
25 changes: 18 additions & 7 deletions pkg/scalers/postgresql_scaler.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type postgreSQLMetadata struct {
query string
dbName string
sslmode string
metricName string
}

var postgreSQLLog = logf.Log.WithName("postgreSQL_scaler")
Expand Down Expand Up @@ -113,6 +114,21 @@ func parsePostgreSQLMetadata(config *ScalerConfig) (*postgreSQLMetadata, error)
}
}

if val, ok := config.TriggerMetadata["metricName"]; ok {
meta.metricName = kedautil.NormalizeString(fmt.Sprintf("postgresql-%s", val))
} else {
if meta.connection != "" {
maskedConnectionString, err := kedautil.MaskPassword(meta.connection)
if err != nil {
return nil, fmt.Errorf("url parsing error %s", err.Error())
}

meta.metricName = kedautil.NormalizeString(fmt.Sprintf("postgresql-%s", maskedConnectionString))
} else {
meta.metricName = kedautil.NormalizeString(fmt.Sprintf("postgresql-%s", meta.dbName))
}
}

return &meta, nil
}

Expand Down Expand Up @@ -177,15 +193,10 @@ func (s *postgreSQLScaler) getActiveNumber() (int, error) {
// GetMetricSpecForScaling returns the MetricSpec for the Horizontal Pod Autoscaler
func (s *postgreSQLScaler) GetMetricSpecForScaling() []v2beta2.MetricSpec {
targetQueryValue := resource.NewQuantity(int64(s.metadata.targetQueryValue), resource.DecimalSI)
metricName := "postgresql"
if s.metadata.connection != "" {
metricName = kedautil.NormalizeString(fmt.Sprintf("%s-%s", metricName, s.metadata.connection))
} else {
metricName = kedautil.NormalizeString(fmt.Sprintf("%s-%s", metricName, s.metadata.dbName))
}

externalMetric := &v2beta2.ExternalMetricSource{
Metric: v2beta2.MetricIdentifier{
Name: metricName,
Name: s.metadata.metricName,
},
Target: v2beta2.MetricTarget{
Type: v2beta2.AverageValueMetricType,
Expand Down
22 changes: 18 additions & 4 deletions pkg/scalers/postgresql_scaler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,38 @@ type parsePostgreSQLMetadataTestData struct {

type postgreSQLMetricIdentifier struct {
metadataTestData *parsePostgreSQLMetadataTestData
resolvedEnv map[string]string
authParam map[string]string
name string
}

var testPostgreSQLMetdata = []parsePostgreSQLMetadataTestData{
// connection
// connection with username and password
{metadata: map[string]string{"query": "test_query", "targetQueryValue": "5", "connectionFromEnv": "test_connection_string"}},
// connection with username
{metadata: map[string]string{"query": "test_query", "targetQueryValue": "5", "connectionFromEnv": "test_connection_string2"}},
// connection without username and password
{metadata: map[string]string{"query": "test_query", "targetQueryValue": "5", "connection": "postgresql://localhost:5432"}},
// connection with password + metricname
{metadata: map[string]string{"query": "test_query", "targetQueryValue": "5", "connection": "postgresql://username:password@localhost:5432", "metricName": "scaler_sql_data2"}},
// dbName
{metadata: map[string]string{"query": "test_query", "targetQueryValue": "5", "host": "test_host", "port": "test_port", "userName": "test_user_name", "dbName": "test_db_name", "sslmode": "test_ssl_mode"}},
// dbName + metricName
{metadata: map[string]string{"query": "test_query", "targetQueryValue": "5", "host": "test_host", "port": "test_port", "userName": "test_user_name", "dbName": "test_db_name", "sslmode": "test_ssl_mode", "metricName": "scaler_sql_data"}},
}

var postgreSQLMetricIdentifiers = []postgreSQLMetricIdentifier{
{&testPostgreSQLMetdata[0], "postgresql-test_connection_string"},
{&testPostgreSQLMetdata[1], "postgresql-test_db_name"},
{&testPostgreSQLMetdata[0], map[string]string{"test_connection_string": "postgresql://localhost:5432"}, nil, "postgresql-postgresql---localhost-5432"},
{&testPostgreSQLMetdata[1], map[string]string{"test_connection_string2": "postgresql://test@localhost"}, nil, "postgresql-postgresql---test@localhost"},
{&testPostgreSQLMetdata[2], nil, map[string]string{"connection": "postgresql://user:password@localhost:5432/dbname"}, "postgresql-postgresql---user-xxx@localhost-5432-dbname"},
{&testPostgreSQLMetdata[3], nil, map[string]string{"connection": "postgresql://Username123:secret@localhost"}, "postgresql-scaler_sql_data2"},
{&testPostgreSQLMetdata[4], nil, map[string]string{"connection": "postgresql://user:password@localhost:5432/dbname?app_name=test"}, "postgresql-postgresql---user-xxx@localhost-5432-dbname?app_name=test"},
{&testPostgreSQLMetdata[5], nil, map[string]string{"connection": "postgresql://Username123:secret@localhost"}, "postgresql-scaler_sql_data"},
}

func TestPosgresSQLGetMetricSpecForScaling(t *testing.T) {
for _, testData := range postgreSQLMetricIdentifiers {
meta, err := parsePostgreSQLMetadata(&ScalerConfig{ResolvedEnv: map[string]string{"test_connection_string": "test_connection_string"}, TriggerMetadata: testData.metadataTestData.metadata, AuthParams: nil})
meta, err := parsePostgreSQLMetadata(&ScalerConfig{ResolvedEnv: testData.resolvedEnv, TriggerMetadata: testData.metadataTestData.metadata, AuthParams: testData.authParam})
if err != nil {
t.Fatal("Could not parse metadata:", err)
}
Expand Down
15 changes: 15 additions & 0 deletions pkg/util/normalize_string.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package util

import (
"net/url"
"strings"
)

Expand All @@ -12,3 +13,17 @@ func NormalizeString(s string) string {
s = strings.ReplaceAll(s, "%", "-")
return s
}

// MaskPassword will parse a url and returned a masked version or an error
func MaskPassword(s string) (string, error) {
url, err := url.Parse(s)
if err != nil {
return "", err
}

if password, ok := url.User.Password(); ok {
return strings.ReplaceAll(s, password, "xxx"), nil
}

return s, nil
}

0 comments on commit 9c86c7c

Please sign in to comment.