diff --git a/CHANGELOG.md b/CHANGELOG.md index bb4c2e5646a..449f61bef8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ To learn more about active deprecations, we recommend checking [GitHub Discussio - **CloudEventSource**: Provide ClusterCloudEventSource around the management of ScaledJobs resources ([#3523](https://github.com/kedacore/keda/issues/3523)) - **CloudEventSource**: Provide ClusterCloudEventSource around the management of TriggerAuthentication/ClusterTriggerAuthentication resources ([#3524](https://github.com/kedacore/keda/issues/3524)) - **Github Action**: Fix panic when env for runnerScopeFromEnv or ownerFromEnv is empty ([#6156](https://github.com/kedacore/keda/issues/6156)) +- **RabbitMQ Scaler**: provide separate paremeters for user and password ([#2513](https://github.com/kedacore/keda/issues/2513)) #### Experimental diff --git a/pkg/scalers/rabbitmq_scaler.go b/pkg/scalers/rabbitmq_scaler.go index f30d92fa13a..860228d3a99 100644 --- a/pkg/scalers/rabbitmq_scaler.go +++ b/pkg/scalers/rabbitmq_scaler.go @@ -8,6 +8,7 @@ import ( "net/http" "net/url" "path" + "reflect" "regexp" "strconv" "strings" @@ -83,6 +84,9 @@ type rabbitMQMetadata struct { timeout time.Duration // custom http timeout for a specific trigger triggerIndex int // scaler index + username string + password string + // TLS ca string cert string @@ -149,12 +153,20 @@ func NewRabbitMQScaler(config *scalersconfig.ScalerConfig) (Scaler, error) { if meta.protocol == amqpProtocol { // Override vhost if requested. host := meta.host - if meta.vhostName != "" { + if meta.vhostName != "" || (meta.username != "" && meta.password != "") { hostURI, err := amqp.ParseURI(host) if err != nil { return nil, fmt.Errorf("error parsing rabbitmq connection string: %w", err) } - hostURI.Vhost = meta.vhostName + if meta.vhostName != "" { + hostURI.Vhost = meta.vhostName + } + + if meta.username != "" && meta.password != "" { + hostURI.Username = meta.username + hostURI.Password = meta.password + } + host = hostURI.String() } @@ -232,6 +244,28 @@ func resolveTLSAuthParams(config *scalersconfig.ScalerConfig, meta *rabbitMQMeta return nil } +func resolveAuth(config *scalersconfig.ScalerConfig, meta *rabbitMQMetadata) error { + usernameVal, err := getParameterFromConfigV2(config, "username", reflect.TypeOf(meta.username), + UseAuthentication(true), UseResolvedEnv(true), IsOptional(true)) + if err != nil { + return err + } + meta.username = usernameVal.(string) + + passwordVal, err := getParameterFromConfigV2(config, "password", reflect.TypeOf(meta.username), + UseAuthentication(true), UseResolvedEnv(true), IsOptional(true)) + if err != nil { + return err + } + meta.password = passwordVal.(string) + + if (meta.username != "" || meta.password != "") && (meta.username == "" || meta.password == "") { + return fmt.Errorf("username and password must be given together") + } + + return nil +} + func parseRabbitMQMetadata(config *scalersconfig.ScalerConfig) (*rabbitMQMetadata, error) { meta := rabbitMQMetadata{ connectionName: connectionName(config), @@ -252,6 +286,11 @@ func parseRabbitMQMetadata(config *scalersconfig.ScalerConfig) (*rabbitMQMetadat return nil, err } + // Resolve username and password + if err := resolveAuth(config, &meta); err != nil { + return nil, err + } + meta.keyPassword = config.AuthParams["keyPassword"] if config.PodIdentity.Provider == v1alpha1.PodIdentityProviderAzureWorkload { @@ -596,6 +635,10 @@ func (s *rabbitMQScaler) getQueueInfoViaHTTP(ctx context.Context) (*queueInfo, e vhost, subpaths := getVhostAndPathFromURL(parsedURL.Path, s.metadata.vhostName) parsedURL.Path = subpaths + if s.metadata.username != "" && s.metadata.password != "" { + parsedURL.User = url.UserPassword(s.metadata.username, s.metadata.password) + } + var getQueueInfoManagementURI string if s.metadata.useRegex { getQueueInfoManagementURI = fmt.Sprintf("%s/api/queues%s?page=1&use_regex=true&pagination=false&name=%s&page_size=%d", parsedURL.String(), vhost, url.QueryEscape(s.metadata.queueName), s.metadata.pageSize) diff --git a/pkg/scalers/rabbitmq_scaler_test.go b/pkg/scalers/rabbitmq_scaler_test.go index ef705757a3c..dd9c3f900b8 100644 --- a/pkg/scalers/rabbitmq_scaler_test.go +++ b/pkg/scalers/rabbitmq_scaler_test.go @@ -18,7 +18,9 @@ import ( ) const ( - host = "myHostSecret" + host = "myHostSecret" + rabbitMQUsername = "myUsernameSecret" + rabbitMQPassword = "myPasswordSecret" ) type parseRabbitMQMetadataTestData struct { @@ -43,7 +45,9 @@ type rabbitMQMetricIdentifier struct { } var sampleRabbitMqResolvedEnv = map[string]string{ - host: "amqp://user:sercet@somehost.com:5236/vhost", + host: "amqp://user:sercet@somehost.com:5236/vhost", + rabbitMQUsername: "user", + rabbitMQPassword: "Password", } var testRabbitMQMetadata = []parseRabbitMQMetadataTestData{ @@ -151,6 +155,18 @@ var testRabbitMQAuthParamData = []parseRabbitMQAuthParamTestData{ {map[string]string{"queueName": "sample", "hostFromEnv": host}, v1alpha1.AuthPodIdentity{}, map[string]string{"tls": "enable", "ca": "caaa", "cert": "ceert"}, true, true, false}, // failure, TLS invalid {map[string]string{"queueName": "sample", "hostFromEnv": host}, v1alpha1.AuthPodIdentity{}, map[string]string{"tls": "yes", "ca": "caaa", "cert": "ceert", "key": "kee"}, true, true, false}, + // success, username and password + {map[string]string{"queueName": "sample", "hostFromEnv": host}, v1alpha1.AuthPodIdentity{}, map[string]string{"username": "user", "password": "PASSWORD"}, false, false, false}, + // failure, username but no password + {map[string]string{"queueName": "sample", "hostFromEnv": host}, v1alpha1.AuthPodIdentity{}, map[string]string{"username": "user"}, true, false, false}, + // failure, password but no username + {map[string]string{"queueName": "sample", "hostFromEnv": host}, v1alpha1.AuthPodIdentity{}, map[string]string{"password": "PASSWORD"}, true, false, false}, + // success, username and password from env + {map[string]string{"queueName": "sample", "hostFromEnv": host, "usernameFromEnv": rabbitMQUsername, "passwordFromEnv": rabbitMQPassword}, v1alpha1.AuthPodIdentity{}, map[string]string{}, false, false, false}, + // failure, username from env but not password + {map[string]string{"queueName": "sample", "hostFromEnv": host, "usernameFromEnv": rabbitMQUsername}, v1alpha1.AuthPodIdentity{}, map[string]string{}, true, false, false}, + // failure, password from env but not username + {map[string]string{"queueName": "sample", "hostFromEnv": host, "passwordFromEnv": rabbitMQPassword}, v1alpha1.AuthPodIdentity{}, map[string]string{}, true, false, false}, // success, WorkloadIdentity {map[string]string{"queueName": "sample", "hostFromEnv": host, "protocol": "http"}, v1alpha1.AuthPodIdentity{Provider: v1alpha1.PodIdentityProviderAzureWorkload, IdentityID: kedautil.StringPointer("client-id")}, map[string]string{"workloadIdentityResource": "rabbitmq-resource-id"}, false, false, true}, // failure, WoekloadIdentity not supported for amqp diff --git a/tests/scalers/rabbitmq/rabbitmq_helper.go b/tests/scalers/rabbitmq/rabbitmq_helper.go index 6f22b178d95..d0a78e821e4 100644 --- a/tests/scalers/rabbitmq/rabbitmq_helper.go +++ b/tests/scalers/rabbitmq/rabbitmq_helper.go @@ -139,6 +139,47 @@ data: --- apiVersion: apps/v1 kind: Deployment +metadata: + name: {{.DeploymentName}} + namespace: {{.TestNamespace}} + labels: + app: {{.DeploymentName}} +spec: + replicas: 0 + selector: + matchLabels: + app: {{.DeploymentName}} + template: + metadata: + labels: + app: {{.DeploymentName}} + spec: + containers: + - name: rabbitmq-consumer + image: ghcr.io/kedacore/tests-rabbitmq + imagePullPolicy: Always + command: + - receive + args: + - '{{.Connection}}' + envFrom: + - secretRef: + name: {{.SecretName}} +` + + RMQTargetDeploymentWithAuthEnvTemplate = ` +apiVersion: v1 +kind: Secret +metadata: + name: {{.SecretName}} + namespace: {{.TestNamespace}} +data: + RabbitApiHost: {{.Base64Connection}} + RabbitUsername: {{.Base64Username}} + RabbitPassword: {{.Base64Password}} +--- +apiVersion: apps/v1 +kind: Deployment metadata: name: {{.DeploymentName}} namespace: {{.TestNamespace}} diff --git a/tests/scalers/rabbitmq/rabbitmq_queue_amqp_auth/rabbitmq_queue_amqp_auth_test.go b/tests/scalers/rabbitmq/rabbitmq_queue_amqp_auth/rabbitmq_queue_amqp_auth_test.go new file mode 100644 index 00000000000..47acb3e7144 --- /dev/null +++ b/tests/scalers/rabbitmq/rabbitmq_queue_amqp_auth/rabbitmq_queue_amqp_auth_test.go @@ -0,0 +1,258 @@ +//go:build e2e +// +build e2e + +package rabbitmq_queue_amqp_auth_test + +import ( + "encoding/base64" + "fmt" + "testing" + + "github.com/joho/godotenv" + "github.com/stretchr/testify/assert" + "k8s.io/client-go/kubernetes" + + . "github.com/kedacore/keda/v2/tests/helper" + . "github.com/kedacore/keda/v2/tests/scalers/rabbitmq" +) + +// Load environment variables from .env file +var _ = godotenv.Load("../../../.env") + +const ( + testName = "rmq-queue-amqp-test" +) + +var ( + testNamespace = fmt.Sprintf("%s-ns", testName) + rmqNamespace = fmt.Sprintf("%s-rmq", testName) + deploymentName = fmt.Sprintf("%s-deployment", testName) + triggerAuthenticationName = fmt.Sprintf("%s-ta", testName) + secretName = fmt.Sprintf("%s-secret", testName) + scaledObjectName = fmt.Sprintf("%s-so", testName) + queueName = "hello" + user = fmt.Sprintf("%s-user", testName) + password = fmt.Sprintf("%s-password", testName) + vhost = "/" + NoAuthConnectionString = fmt.Sprintf("amqp://rabbitmq.%s.svc.cluster.local", rmqNamespace) + connectionString = fmt.Sprintf("amqp://%s:%s@rabbitmq.%s.svc.cluster.local", user, password, rmqNamespace) + messageCount = 100 +) + +const ( + scaledObjectAuthFromSecretTemplate = ` +--- +apiVersion: keda.sh/v1alpha1 +kind: ScaledObject +metadata: + name: {{.ScaledObjectName}} + namespace: {{.TestNamespace}} +spec: + scaleTargetRef: + name: {{.DeploymentName}} + pollingInterval: 5 + cooldownPeriod: 10 + minReplicaCount: 0 + maxReplicaCount: 4 + triggers: + - type: rabbitmq + metadata: + queueName: {{.QueueName}} + hostFromEnv: RabbitApiHost + mode: QueueLength + value: '10' + activationValue: '5' + authenticationRef: + name: {{.TriggerAuthenticationName}} +` + + triggerAuthenticationTemplate = ` +apiVersion: keda.sh/v1alpha1 +kind: TriggerAuthentication +metadata: + name: {{.TriggerAuthenticationName}} + namespace: {{.TestNamespace}} +spec: + secretTargetRef: + - parameter: username + name: {{.SecretName}} + key: RabbitUsername + - parameter: password + name: {{.SecretName}} + key: RabbitPassword +` + invalidUsernameAndPasswordTriggerAuthenticationTemplate = ` +apiVersion: keda.sh/v1alpha1 +kind: TriggerAuthentication +metadata: + name: {{.TriggerAuthenticationName}} + namespace: {{.TestNamespace}} +spec: + secretTargetRef: + - parameter: username + name: {{.SecretName}} + key: Rabbit-Username + - parameter: password + name: {{.SecretName}} + key: Rabbit-Password +` + + invalidPasswordTriggerAuthenticationTemplate = ` +apiVersion: keda.sh/v1alpha1 +kind: TriggerAuthentication +metadata: + name: {{.TriggerAuthenticationName}} + namespace: {{.TestNamespace}} +spec: + secretTargetRef: + - parameter: username + name: {{.SecretName}} + key: RabbitUsername + - parameter: password + name: {{.SecretName}} + key: Rabbit-Password +` + + scaledObjectAuthFromEnvTemplate = ` +apiVersion: keda.sh/v1alpha1 +kind: ScaledObject +metadata: + name: {{.ScaledObjectName}} + namespace: {{.TestNamespace}} +spec: + scaleTargetRef: + name: {{.DeploymentName}} + pollingInterval: 5 + cooldownPeriod: 10 + minReplicaCount: 0 + maxReplicaCount: 4 + triggers: + - type: rabbitmq + metadata: + queueName: {{.QueueName}} + hostFromEnv: RabbitApiHost + usernameFromEnv: RabbitUsername + passwordFromEnv: RabbitPassword + mode: QueueLength + value: '10' + activationValue: '5' +` +) + +type templateData struct { + TestNamespace string + DeploymentName string + ScaledObjectName string + TriggerAuthenticationName string + SecretName string + QueueName string + Username, Base64Username string + Password, Base64Password string + Connection, Base64Connection string + FullConnection string +} + +func TestScaler(t *testing.T) { + // setup + t.Log("--- setting up ---") + kc := GetKubernetesClient(t) + data, templates := getTemplateData() + t.Cleanup(func() { + DeleteKubernetesResources(t, testNamespace, data, templates) + RMQUninstall(t, rmqNamespace, user, password, vhost, WithoutOAuth()) + }) + + // Create kubernetes resources + RMQInstall(t, kc, rmqNamespace, user, password, vhost, WithoutOAuth()) + CreateKubernetesResources(t, kc, testNamespace, data, templates) + + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, 0, 60, 1), + "replica count should be 0 after 1 minute") + + testAuthFromSecret(t, kc, data) + testAuthFromEnv(t, kc, data) + + testInvalidPassword(t, kc, data) + testInvalidUsernameAndPassword(t, kc, data) + + testActivationValue(t, kc) +} + +func getTemplateData() (templateData, []Template) { + return templateData{ + TestNamespace: testNamespace, + DeploymentName: deploymentName, + ScaledObjectName: scaledObjectName, + TriggerAuthenticationName: triggerAuthenticationName, + SecretName: secretName, + QueueName: queueName, + Username: user, + Base64Username: base64.StdEncoding.EncodeToString([]byte(user)), + Password: password, + Base64Password: base64.StdEncoding.EncodeToString([]byte(password)), + Connection: connectionString, + Base64Connection: base64.StdEncoding.EncodeToString([]byte(NoAuthConnectionString)), + }, []Template{ + {Name: "deploymentTemplate", Config: RMQTargetDeploymentWithAuthEnvTemplate}, + } +} + +func testAuthFromSecret(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing scale out ---") + KubectlApplyWithTemplate(t, data, "scaledObjectAuthFromSecretTemplate", scaledObjectAuthFromSecretTemplate) + defer KubectlDeleteWithTemplate(t, data, "scaledObjectAuthFromSecretTemplate", scaledObjectAuthFromSecretTemplate) + KubectlApplyWithTemplate(t, data, "triggerAuthenticationTemplate", triggerAuthenticationTemplate) + defer KubectlDeleteWithTemplate(t, data, "triggerAuthenticationTemplate", triggerAuthenticationTemplate) + + RMQPublishMessages(t, rmqNamespace, connectionString, queueName, messageCount) + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, 4, 60, 1), + "replica count should be 4 after 1 minute") + + t.Log("--- testing scale in ---") + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, 0, 60, 1), + "replica count should be 0 after 1 minute") +} + +func testAuthFromEnv(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing scale out ---") + KubectlApplyWithTemplate(t, data, "scaledObjectAuthFromEnvTemplate", scaledObjectAuthFromEnvTemplate) + defer KubectlDeleteWithTemplate(t, data, "scaledObjectAuthFromEnvTemplate", scaledObjectAuthFromEnvTemplate) + + RMQPublishMessages(t, rmqNamespace, connectionString, queueName, messageCount) + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, 4, 60, 1), + "replica count should be 4 after 1 minute") + + t.Log("--- testing scale in ---") + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, 0, 60, 1), + "replica count should be 0 after 1 minute") +} + +func testInvalidPassword(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing invalid password ---") + KubectlApplyWithTemplate(t, data, "scaledObjectAuthFromSecretTemplate", scaledObjectAuthFromSecretTemplate) + defer KubectlDeleteWithTemplate(t, data, "scaledObjectAuthFromSecretTemplate", scaledObjectAuthFromSecretTemplate) + KubectlApplyWithTemplate(t, data, "invalidPasswordTriggerAuthenticationTemplate", invalidPasswordTriggerAuthenticationTemplate) + defer KubectlDeleteWithTemplate(t, data, "invalidPasswordTriggerAuthenticationTemplate", invalidPasswordTriggerAuthenticationTemplate) + + // Shouldn't scale pods + AssertReplicaCountNotChangeDuringTimePeriod(t, kc, deploymentName, testNamespace, 0, 30) +} + +func testInvalidUsernameAndPassword(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing invalid username and password ---") + KubectlApplyWithTemplate(t, data, "scaledObjectAuthFromSecretTemplate", scaledObjectAuthFromSecretTemplate) + defer KubectlDeleteWithTemplate(t, data, "scaledObjectAuthFromSecretTemplate", scaledObjectAuthFromSecretTemplate) + KubectlApplyWithTemplate(t, data, "invalidUsernameAndPasswordTriggerAuthenticationTemplate", invalidUsernameAndPasswordTriggerAuthenticationTemplate) + defer KubectlDeleteWithTemplate(t, data, "invalidUsernameAndPasswordTriggerAuthenticationTemplate", invalidUsernameAndPasswordTriggerAuthenticationTemplate) + + // Shouldn't scale pods + AssertReplicaCountNotChangeDuringTimePeriod(t, kc, deploymentName, testNamespace, 0, 30) +} + +func testActivationValue(t *testing.T, kc *kubernetes.Clientset) { + t.Log("--- testing activation value ---") + messagesToQueue := 3 + RMQPublishMessages(t, rmqNamespace, connectionString, queueName, messagesToQueue) + + AssertReplicaCountNotChangeDuringTimePeriod(t, kc, deploymentName, testNamespace, 0, 60) +} diff --git a/tests/scalers/rabbitmq/rabbitmq_queue_http_auth/rabbitmq_queue_http_auth_test.go b/tests/scalers/rabbitmq/rabbitmq_queue_http_auth/rabbitmq_queue_http_auth_test.go new file mode 100644 index 00000000000..a95d1924a8e --- /dev/null +++ b/tests/scalers/rabbitmq/rabbitmq_queue_http_auth/rabbitmq_queue_http_auth_test.go @@ -0,0 +1,258 @@ +//go:build e2e +// +build e2e + +package rabbitmq_queue_http_test + +import ( + "encoding/base64" + "fmt" + "testing" + + "github.com/joho/godotenv" + "github.com/stretchr/testify/assert" + "k8s.io/client-go/kubernetes" + + . "github.com/kedacore/keda/v2/tests/helper" + . "github.com/kedacore/keda/v2/tests/scalers/rabbitmq" +) + +// Load environment variables from .env file +var _ = godotenv.Load("../../../.env") + +const ( + testName = "rmq-queue-http-test" +) + +var ( + testNamespace = fmt.Sprintf("%s-ns", testName) + rmqNamespace = fmt.Sprintf("%s-rmq", testName) + deploymentName = fmt.Sprintf("%s-deployment", testName) + triggerAuthenticationName = fmt.Sprintf("%s-ta", testName) + secretName = fmt.Sprintf("%s-secret", testName) + scaledObjectName = fmt.Sprintf("%s-so", testName) + queueName = "hello" + user = fmt.Sprintf("%s-user", testName) + password = fmt.Sprintf("%s-password", testName) + vhost = "/" + NoAuthConnectionString = fmt.Sprintf("http://rabbitmq.%s.svc.cluster.local", rmqNamespace) + connectionString = fmt.Sprintf("amqp://%s:%s@rabbitmq.%s.svc.cluster.local", user, password, rmqNamespace) + messageCount = 100 +) + +const ( + scaledObjectAuthFromSecretTemplate = ` +--- +apiVersion: keda.sh/v1alpha1 +kind: ScaledObject +metadata: + name: {{.ScaledObjectName}} + namespace: {{.TestNamespace}} +spec: + scaleTargetRef: + name: {{.DeploymentName}} + pollingInterval: 5 + cooldownPeriod: 10 + minReplicaCount: 0 + maxReplicaCount: 4 + triggers: + - type: rabbitmq + metadata: + queueName: {{.QueueName}} + hostFromEnv: RabbitApiHost + mode: QueueLength + value: '10' + activationValue: '5' + authenticationRef: + name: {{.TriggerAuthenticationName}} +` + + triggerAuthenticationTemplate = ` +apiVersion: keda.sh/v1alpha1 +kind: TriggerAuthentication +metadata: + name: {{.TriggerAuthenticationName}} + namespace: {{.TestNamespace}} +spec: + secretTargetRef: + - parameter: username + name: {{.SecretName}} + key: RabbitUsername + - parameter: password + name: {{.SecretName}} + key: RabbitPassword +` + invalidUsernameAndPasswordTriggerAuthenticationTemplate = ` +apiVersion: keda.sh/v1alpha1 +kind: TriggerAuthentication +metadata: + name: {{.TriggerAuthenticationName}} + namespace: {{.TestNamespace}} +spec: + secretTargetRef: + - parameter: username + name: {{.SecretName}} + key: Rabbit-Username + - parameter: password + name: {{.SecretName}} + key: Rabbit-Password +` + + invalidPasswordTriggerAuthenticationTemplate = ` +apiVersion: keda.sh/v1alpha1 +kind: TriggerAuthentication +metadata: + name: {{.TriggerAuthenticationName}} + namespace: {{.TestNamespace}} +spec: + secretTargetRef: + - parameter: username + name: {{.SecretName}} + key: RabbitUsername + - parameter: password + name: {{.SecretName}} + key: Rabbit-Password +` + + scaledObjectAuthFromEnvTemplate = ` +apiVersion: keda.sh/v1alpha1 +kind: ScaledObject +metadata: + name: {{.ScaledObjectName}} + namespace: {{.TestNamespace}} +spec: + scaleTargetRef: + name: {{.DeploymentName}} + pollingInterval: 5 + cooldownPeriod: 10 + minReplicaCount: 0 + maxReplicaCount: 4 + triggers: + - type: rabbitmq + metadata: + queueName: {{.QueueName}} + hostFromEnv: RabbitApiHost + usernameFromEnv: RabbitUsername + passwordFromEnv: RabbitPassword + mode: QueueLength + value: '10' + activationValue: '5' +` +) + +type templateData struct { + TestNamespace string + DeploymentName string + ScaledObjectName string + TriggerAuthenticationName string + SecretName string + QueueName string + Username, Base64Username string + Password, Base64Password string + Connection, Base64Connection string + FullConnection string +} + +func TestScaler(t *testing.T) { + // setup + t.Log("--- setting up ---") + kc := GetKubernetesClient(t) + data, templates := getTemplateData() + t.Cleanup(func() { + DeleteKubernetesResources(t, testNamespace, data, templates) + RMQUninstall(t, rmqNamespace, user, password, vhost, WithoutOAuth()) + }) + + // Create kubernetes resources + RMQInstall(t, kc, rmqNamespace, user, password, vhost, WithoutOAuth()) + CreateKubernetesResources(t, kc, testNamespace, data, templates) + + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, 0, 60, 1), + "replica count should be 0 after 1 minute") + + testAuthFromSecret(t, kc, data) + testAuthFromEnv(t, kc, data) + + testInvalidPassword(t, kc, data) + testInvalidUsernameAndPassword(t, kc, data) + + testActivationValue(t, kc) +} + +func getTemplateData() (templateData, []Template) { + return templateData{ + TestNamespace: testNamespace, + DeploymentName: deploymentName, + ScaledObjectName: scaledObjectName, + TriggerAuthenticationName: triggerAuthenticationName, + SecretName: secretName, + QueueName: queueName, + Username: user, + Base64Username: base64.StdEncoding.EncodeToString([]byte(user)), + Password: password, + Base64Password: base64.StdEncoding.EncodeToString([]byte(password)), + Connection: connectionString, + Base64Connection: base64.StdEncoding.EncodeToString([]byte(NoAuthConnectionString)), + }, []Template{ + {Name: "deploymentTemplate", Config: RMQTargetDeploymentWithAuthEnvTemplate}, + } +} + +func testAuthFromSecret(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing scale out ---") + KubectlApplyWithTemplate(t, data, "scaledObjectAuthFromSecretTemplate", scaledObjectAuthFromSecretTemplate) + defer KubectlDeleteWithTemplate(t, data, "scaledObjectAuthFromSecretTemplate", scaledObjectAuthFromSecretTemplate) + KubectlApplyWithTemplate(t, data, "triggerAuthenticationTemplate", triggerAuthenticationTemplate) + defer KubectlDeleteWithTemplate(t, data, "triggerAuthenticationTemplate", triggerAuthenticationTemplate) + + RMQPublishMessages(t, rmqNamespace, connectionString, queueName, messageCount) + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, 4, 60, 1), + "replica count should be 4 after 1 minute") + + t.Log("--- testing scale in ---") + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, 0, 60, 1), + "replica count should be 0 after 1 minute") +} + +func testAuthFromEnv(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing scale out ---") + KubectlApplyWithTemplate(t, data, "scaledObjectAuthFromEnvTemplate", scaledObjectAuthFromEnvTemplate) + defer KubectlDeleteWithTemplate(t, data, "scaledObjectAuthFromEnvTemplate", scaledObjectAuthFromEnvTemplate) + + RMQPublishMessages(t, rmqNamespace, connectionString, queueName, messageCount) + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, 4, 60, 1), + "replica count should be 4 after 1 minute") + + t.Log("--- testing scale in ---") + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, 0, 60, 1), + "replica count should be 0 after 1 minute") +} + +func testInvalidPassword(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing invalid password ---") + KubectlApplyWithTemplate(t, data, "scaledObjectAuthFromSecretTemplate", scaledObjectAuthFromSecretTemplate) + defer KubectlDeleteWithTemplate(t, data, "scaledObjectAuthFromSecretTemplate", scaledObjectAuthFromSecretTemplate) + KubectlApplyWithTemplate(t, data, "invalidPasswordTriggerAuthenticationTemplate", invalidPasswordTriggerAuthenticationTemplate) + defer KubectlDeleteWithTemplate(t, data, "invalidPasswordTriggerAuthenticationTemplate", invalidPasswordTriggerAuthenticationTemplate) + + // Shouldn't scale pods + AssertReplicaCountNotChangeDuringTimePeriod(t, kc, deploymentName, testNamespace, 0, 30) +} + +func testInvalidUsernameAndPassword(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing invalid username and password ---") + KubectlApplyWithTemplate(t, data, "scaledObjectAuthFromSecretTemplate", scaledObjectAuthFromSecretTemplate) + defer KubectlDeleteWithTemplate(t, data, "scaledObjectAuthFromSecretTemplate", scaledObjectAuthFromSecretTemplate) + KubectlApplyWithTemplate(t, data, "invalidUsernameAndPasswordTriggerAuthenticationTemplate", invalidUsernameAndPasswordTriggerAuthenticationTemplate) + defer KubectlDeleteWithTemplate(t, data, "invalidUsernameAndPasswordTriggerAuthenticationTemplate", invalidUsernameAndPasswordTriggerAuthenticationTemplate) + + // Shouldn't scale pods + AssertReplicaCountNotChangeDuringTimePeriod(t, kc, deploymentName, testNamespace, 0, 30) +} + +func testActivationValue(t *testing.T, kc *kubernetes.Clientset) { + t.Log("--- testing activation value ---") + messagesToQueue := 3 + RMQPublishMessages(t, rmqNamespace, connectionString, queueName, messagesToQueue) + + AssertReplicaCountNotChangeDuringTimePeriod(t, kc, deploymentName, testNamespace, 0, 60) +}