Skip to content

Commit

Permalink
feat: add TLS support for IBM MQ scaler (#5976)
Browse files Browse the repository at this point in the history
* feat: add TLS auth support for IBM MQ scaler

Signed-off-by: rickbrouwer <75609067+rickbrouwer@users.noreply.github.com>

* fix: fix ibmmq scaler test

Signed-off-by: Rick Brouwer <rickbrouwer@gmail.com>

* fix: correct httpClient

Co-authored-by: Jorge Turrado Ferrero <Jorge_turrado@hotmail.es>
Signed-off-by: rickbrouwer <75609067+rickbrouwer@users.noreply.github.com>

---------

Signed-off-by: rickbrouwer <75609067+rickbrouwer@users.noreply.github.com>
Signed-off-by: Rick Brouwer <rickbrouwer@gmail.com>
Co-authored-by: Jorge Turrado Ferrero <Jorge_turrado@hotmail.es>
  • Loading branch information
rickbrouwer and JorTurFer committed Jul 25, 2024
1 parent ebc8975 commit 857c09f
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 18 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Here is an overview of all new **experimental** features:
- **Cassandra Scaler**: Add TLS support for cassandra scaler ([#5802](https://github.com/kedacore/keda/issues/5802))
- **GCP Scalers**: Added custom time horizon in GCP scalers ([#5778](https://github.com/kedacore/keda/issues/5778))
- **GitHub Scaler**: Fixed pagination, fetching repository list ([#5738](https://github.com/kedacore/keda/issues/5738))
- **IBM MQ Scaler**: Add TLS support for IBM MQ scaler ([#5974](https://github.com/kedacore/keda/issues/5974))
- **Kafka**: Fix logic to scale to zero on invalid offset even with earliest offsetResetPolicy ([#5689](https://github.com/kedacore/keda/issues/5689))
- **MYSQL Scaler**: Add support to fetch username from env ([#5883](https://github.com/kedacore/keda/issues/5883))

Expand Down
70 changes: 53 additions & 17 deletions pkg/scalers/ibmmq_scaler.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type IBMMQScaler struct {
metricType v2.MetricTargetType
metadata *IBMMQMetadata
defaultHTTPTimeout time.Duration
httpClient *http.Client
logger logr.Logger
}

Expand All @@ -45,6 +46,13 @@ type IBMMQMetadata struct {
activationQueueDepth int64
tlsDisabled bool
triggerIndex int

// TLS
ca string
cert string
key string
keyPassword string
unsafeSsl bool
}

// CommandResponse Full structured response from MQ admin REST query
Expand Down Expand Up @@ -75,16 +83,31 @@ func NewIBMMQScaler(config *scalersconfig.ScalerConfig) (Scaler, error) {
return nil, fmt.Errorf("error parsing IBM MQ metadata: %w", err)
}

httpClient := kedautil.CreateHTTPClient(config.GlobalHTTPTimeout, meta.tlsDisabled)

// Configure TLS if cert and key are specified
if meta.cert != "" && meta.key != "" {
tlsConfig, err := kedautil.NewTLSConfigWithPassword(meta.cert, meta.key, meta.keyPassword, meta.ca, meta.unsafeSsl)
if err != nil {
return nil, err
}
httpClient.Transport = kedautil.CreateHTTPTransportWithTLSConfig(tlsConfig)
}

return &IBMMQScaler{
metricType: metricType,
metadata: meta,
defaultHTTPTimeout: config.GlobalHTTPTimeout,
httpClient: httpClient,
logger: InitializeLogger(config, "ibm_mq_scaler"),
}, nil
}

// Close closes and returns nil
func (s *IBMMQScaler) Close(context.Context) error {
if s.httpClient != nil {
s.httpClient.CloseIdleConnections()
}
return nil
}

Expand Down Expand Up @@ -144,24 +167,38 @@ func parseIBMMQMetadata(config *scalersconfig.ScalerConfig) (*IBMMQMetadata, err
fmt.Println("No tls setting defined - setting default")
meta.tlsDisabled = defaultTLSDisabled
}
val, ok := config.AuthParams["username"]
switch {
case ok && val != "":

if val, ok := config.AuthParams["username"]; ok && val != "" {
meta.username = val
case config.TriggerMetadata["usernameFromEnv"] != "":
meta.username = config.ResolvedEnv[config.TriggerMetadata["usernameFromEnv"]]
default:
} else if val, ok := config.TriggerMetadata["usernameFromEnv"]; ok && val != "" {
meta.username = config.ResolvedEnv[val]
} else {
return nil, fmt.Errorf("no username given")
}
pwdValue, booleanValue := config.AuthParams["password"] // booleanValue reports whether the type assertion succeeded or not
switch {
case booleanValue && pwdValue != "":
meta.password = pwdValue
case config.TriggerMetadata["passwordFromEnv"] != "":
meta.password = config.ResolvedEnv[config.TriggerMetadata["passwordFromEnv"]]
default:

if val, ok := config.AuthParams["password"]; ok && val != "" {
meta.password = val
} else if val, ok := config.TriggerMetadata["passwordFromEnv"]; ok && val != "" {
meta.password = config.ResolvedEnv[val]
} else {
return nil, fmt.Errorf("no password given")
}

// TLS config (optional)
meta.ca = config.AuthParams["ca"]
meta.cert = config.AuthParams["cert"]
meta.key = config.AuthParams["key"]
meta.keyPassword = config.AuthParams["keyPassword"]

meta.unsafeSsl = false
if val, ok := config.TriggerMetadata["unsafeSsl"]; ok {
boolVal, err := strconv.ParseBool(val)
if err != nil {
return nil, fmt.Errorf("failed to parse unsafeSsl value. Must be either true or false")
}
meta.unsafeSsl = boolVal
}

meta.triggerIndex = config.TriggerIndex
return &meta, nil
}
Expand All @@ -178,19 +215,18 @@ func (s *IBMMQScaler) getQueueDepthViaHTTP(ctx context.Context) (int64, error) {
}
req.Header.Set("ibm-mq-rest-csrf-token", "value")
req.Header.Set("Content-Type", "application/json")
req.SetBasicAuth(s.metadata.username, s.metadata.password)

client := kedautil.CreateHTTPClient(s.defaultHTTPTimeout, s.metadata.tlsDisabled)
req.SetBasicAuth(s.metadata.username, s.metadata.password)

resp, err := client.Do(req)
resp, err := s.httpClient.Do(req)
if err != nil {
return 0, fmt.Errorf("failed to contact MQ via REST: %w", err)
}
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
return 0, fmt.Errorf("failed to ready body of request: %w", err)
return 0, fmt.Errorf("failed to read body of request: %w", err)
}

var response CommandResponse
Expand Down
7 changes: 6 additions & 1 deletion pkg/scalers/ibmmq_scaler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,16 @@ var testIBMMQMetadata = []parseIBMMQMetadataTestData{
{map[string]string{"host": testValidMQQueueURL, "queueManager": "testQueueManager", "queueDepth": "10"}, true, map[string]string{"username": "testUsername", "password": "Pass123"}},
// Invalid URL
{map[string]string{"host": testInvalidMQQueueURL, "queueManager": "testQueueManager", "queueName": "testQueue", "queueDepth": "10"}, true, map[string]string{"username": "testUsername", "password": "Pass123"}},
// Properly formed authParams
// Properly formed authParams Basic Auth
{map[string]string{"host": testValidMQQueueURL, "queueManager": "testQueueManager", "queueName": "testQueue", "queueDepth": "10"}, false, map[string]string{"username": "testUsername", "password": "Pass123"}},
// Properly formed authParams Basic Auth and TLS
{map[string]string{"host": testValidMQQueueURL, "queueManager": "testQueueManager", "queueName": "testQueue", "queueDepth": "10"}, false, map[string]string{"username": "testUsername", "password": "Pass123", "ca": "cavalue", "cert": "certvalue", "key": "keyvalue"}},
// No username provided
{map[string]string{"host": testValidMQQueueURL, "queueManager": "testQueueManager", "queueName": "testQueue", "queueDepth": "10"}, true, map[string]string{"password": "Pass123"}},
// No password provided
{map[string]string{"host": testValidMQQueueURL, "queueManager": "testQueueManager", "queueName": "testQueue", "queueDepth": "10"}, true, map[string]string{"username": "testUsername"}},
// Wrong input unsafeSsl
{map[string]string{"host": testValidMQQueueURL, "queueManager": "testQueueManager", "queueName": "testQueue", "queueDepth": "10", "unsafeSsl": "random"}, true, map[string]string{"username": "testUsername", "password": "Pass123"}},
}

// Test MQ Connection metadata is parsed correctly
Expand Down Expand Up @@ -216,6 +220,7 @@ func TestIBMMQScalerGetQueueDepthViaHTTP(t *testing.T) {
metadata: &IBMMQMetadata{
host: server.URL,
},
httpClient: server.Client(),
}

value, err := scaler.getQueueDepthViaHTTP(context.Background())
Expand Down

0 comments on commit 857c09f

Please sign in to comment.