diff --git a/src/autoscaler/metricsforwarder/config/config.go b/src/autoscaler/metricsforwarder/config/config.go index 743ff79b61..59979c980a 100644 --- a/src/autoscaler/metricsforwarder/config/config.go +++ b/src/autoscaler/metricsforwarder/config/config.go @@ -3,7 +3,9 @@ package config import ( "errors" "fmt" + "net/url" "os" + "strings" "time" "code.cloudfoundry.org/app-autoscaler/src/autoscaler/configutil" @@ -158,17 +160,36 @@ func LoadConfig(filepath string, vcapReader configutil.VCAPConfigurationReader) if !ok { conf.Db[db.StoredProcedureDb] = db.DatabaseConfig{} } + currentStoredProcedureDb.URL, err = vcapReader.MaterializeDBFromService(db.StoredProcedureDb) if err != nil { return &conf, err } + + dbURL, err := url.Parse(currentStoredProcedureDb.URL) + if err != nil { + return &conf, err + } + + if conf.StoredProcedureConfig != nil { + if conf.StoredProcedureConfig.Username != "" { + currentStoredProcedureDb.URL = strings.Replace(currentStoredProcedureDb.URL, dbURL.User.Username(), conf.StoredProcedureConfig.Username, 1) + } + + if conf.StoredProcedureConfig.Password != "" { + bindingPassword, _ := dbURL.User.Password() + currentStoredProcedureDb.URL = strings.Replace(currentStoredProcedureDb.URL, bindingPassword, conf.StoredProcedureConfig.Password, 1) + } + } + conf.Db[db.StoredProcedureDb] = currentStoredProcedureDb } - conf.SyslogConfig.TLS, err = vcapReader.MaterializeTLSConfigFromService("syslog-client") - if err != nil { - return &conf, err - } + } + + conf.SyslogConfig.TLS, err = vcapReader.MaterializeTLSConfigFromService("syslog-client") + if err != nil { + return &conf, err } return &conf, nil diff --git a/src/autoscaler/metricsforwarder/config/config_test.go b/src/autoscaler/metricsforwarder/config/config_test.go index 01c00332a9..148729ec77 100644 --- a/src/autoscaler/metricsforwarder/config/config_test.go +++ b/src/autoscaler/metricsforwarder/config/config_test.go @@ -93,7 +93,7 @@ var _ = Describe("Config", func() { When("VCAP_SERVICES has relational db service bind to app for policy db", func() { BeforeEach(func() { - mockVCAPConfigurationReader.GetServiceCredentialContentReturns(getVcapConfigWithCredImplementation("default"), nil) + mockVCAPConfigurationReader.GetServiceCredentialContentReturns([]byte(`{ "cred_helper_impl": "default" }`), nil) // #nosec G101 expectedDbUrl = "postgres://foo:bar@postgres.example.com:5432/policy_db?sslcert=%2Ftmp%2Fclient_cert.sslcert&sslkey=%2Ftmp%2Fclient_key.sslkey&sslrootcert=%2Ftmp%2Fserver_ca.sslrootcert" // #nosec G101 }) @@ -108,7 +108,7 @@ var _ = Describe("Config", func() { When("storedProcedure_db service is provided and cred_helper_impl is stored_procedure", func() { BeforeEach(func() { - mockVCAPConfigurationReader.GetServiceCredentialContentReturns(getVcapConfigWithCredImplementation("stored_procedure"), nil) + mockVCAPConfigurationReader.GetServiceCredentialContentReturns([]byte(`{ "cred_helper_impl": "stored_procedure" }`), nil) // #nosec G101 expectedDbUrl = "postgres://foo:bar@postgres.example.com:5432/policy_db?sslcert=%2Ftmp%2Fclient_cert.sslcert&sslkey=%2Ftmp%2Fclient_key.sslkey&sslrootcert=%2Ftmp%2Fserver_ca.sslrootcert" // #nosec G101 }) @@ -121,11 +121,39 @@ var _ = Describe("Config", func() { actualDbName := mockVCAPConfigurationReader.MaterializeDBFromServiceArgsForCall(1) Expect(actualDbName).To(Equal(db.StoredProcedureDb)) }) + + When("storedProcedure_db config has username and password", func() { + var storedProcedureUsername, storedProcedurePassword string + + BeforeEach(func() { + storedProcedureUsername = "storedProcedureUsername" + storedProcedurePassword = "storedProcedurePassword" + + mockVCAPConfigurationReader.GetServiceCredentialContentReturns([]byte( + `{ "cred_helper_impl": "stored_procedure", + "stored_procedure_binding_credential_config": { + "username": "`+storedProcedureUsername+`", + "password": "`+storedProcedurePassword+`" + }, + }`), + nil, + ) // #nosec G101 + }) + + It("should prioritize the username and password from the config", func() { + // url should include the username and password from the config + Expect(err).NotTo(HaveOccurred()) + _, storeProcedureFound := conf.Db[db.StoredProcedureDb] + Expect(storeProcedureFound).To(BeTrue()) + Expect(conf.Db[db.StoredProcedureDb].URL).To(ContainSubstring(fmt.Sprintf("%s:%s", storedProcedureUsername, storedProcedurePassword))) + }) + }) }) When("storedProcedure_db service is provided and cred_helper_impl is default", func() { BeforeEach(func() { - mockVCAPConfigurationReader.GetServiceCredentialContentReturns(getVcapConfigWithCredImplementation("default"), nil) + mockVCAPConfigurationReader.GetServiceCredentialContentReturns([]byte( + `{ "cred_helper_impl": "default" }`), nil) // #nosec G101 expectedDbUrl = "postgres://foo:bar@postgres.example.com:5432/policy_db?sslcert=%2Ftmp%2Fclient_cert.sslcert&sslkey=%2Ftmp%2Fclient_key.sslkey&sslrootcert=%2Ftmp%2Fserver_ca.sslrootcert" // #nosec G101 }) @@ -138,7 +166,6 @@ var _ = Describe("Config", func() { When("VCAP_SERVICES has metricsforwarder config", func() { BeforeEach(func() { - mockVCAPConfigurationReader.GetServiceCredentialContentReturns([]byte(` { "cache_cleanup_interval":"10h", "cache_ttl":"90s", @@ -414,7 +441,3 @@ health: }) }) }) - -func getVcapConfigWithCredImplementation(credHelperImplementation string) []byte { - return []byte(`{ "cred_helper_impl": "` + credHelperImplementation + `" }`) // #nosec G101 -} diff --git a/src/autoscaler/models/stored_procedure.go b/src/autoscaler/models/stored_procedure.go index 0693105250..864120c2d9 100644 --- a/src/autoscaler/models/stored_procedure.go +++ b/src/autoscaler/models/stored_procedure.go @@ -6,4 +6,6 @@ type StoredProcedureConfig struct { DropBindingCredentialProcedureName string `yaml:"drop_binding_credential_procedure_name"` DropAllBindingCredentialProcedureName string `yaml:"drop_all_binding_credential_procedure_name"` ValidateBindingCredentialProcedureName string `yaml:"validate_binding_credential_procedure_name"` + Username string `yaml:"username"` + Password string `yaml:"password"` }