forked from cloudfoundry/app-autoscaler
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add mysql support for golang components (cloudfoundry#555)
* add mysql support for golang components * fix typo e to err * update db changelog file with mysql * fix .travis.yml and add comment to Connection function * fix integration test * fix err in integration test * remove dbms from scalingengine.db.changelog.yml * refine the helper.go and related test cases * Format code and fix appmetrics empty error * add transaction rollback
- Loading branch information
Showing
40 changed files
with
980 additions
and
161 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
databaseChangeLog: | ||
- changeSet: | ||
id: 1 | ||
author: aqan213 | ||
dbms: mysql | ||
changes: | ||
- addPrimaryKey: | ||
columnNames: "id,author,filename" | ||
constraintName: "PK_DATABASECHANGELOG" | ||
schemaName: autoscaler | ||
tableName: DATABASECHANGELOG |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ import ( | |
) | ||
|
||
const PostgresDriverName = "postgres" | ||
const MysqlDriverName = "mysql" | ||
|
||
type OrderType uint8 | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package db_test | ||
|
||
import ( | ||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
|
||
"testing" | ||
) | ||
|
||
func TestDb(t *testing.T) { | ||
RegisterFailHandler(Fail) | ||
RunSpecs(t, "Db Suite") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
package db | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
"crypto/tls" | ||
"crypto/x509" | ||
"io/ioutil" | ||
"net/url" | ||
"github.com/go-sql-driver/mysql" | ||
|
||
) | ||
|
||
type Database struct { | ||
DriverName string | ||
DSN string | ||
} | ||
|
||
type MySQLConfig struct { | ||
config *mysql.Config | ||
cert string | ||
} | ||
|
||
/** | ||
This function is used to generate db connection info, for example, | ||
For mysql: | ||
input dbUrl: 'username:password@tcp(localhost:3306)/autoscaler?tls=custom&sslrootcert=db_ca.crt' | ||
return: | ||
&Database{DriverName: "mysql", DSN:"username:password@tcp(localhost:3306)/autoscaler?parseTime=true&tls=custom"} | ||
For postgres: | ||
input dbUrl: postgres://postgres:password@localhost:5432/autoscaler?sslmode=disable | ||
return: | ||
&Database{DriverName: "postgres", DSN:"postgres://postgres:password@localhost:5432/autoscaler?sslmode=disable" | ||
**/ | ||
func GetConnection(dbUrl string) (*Database, error) { | ||
database := &Database{} | ||
|
||
database.DriverName = detectDirver(dbUrl) | ||
|
||
switch database.DriverName { | ||
case MysqlDriverName: | ||
cfg, err := parseMySQLURL(dbUrl) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
err = registerConfig(cfg) | ||
if err != nil { | ||
return nil, err | ||
} | ||
database.DSN = cfg.config.FormatDSN() | ||
case PostgresDriverName: | ||
database.DSN = dbUrl | ||
} | ||
return database, nil | ||
} | ||
|
||
func registerConfig(cfg *MySQLConfig) error { | ||
tlsValue := cfg.config.TLSConfig | ||
if _, isBool := readBool(tlsValue); isBool || tlsValue == "" || strings.ToLower(tlsValue) == "skip-verify" || strings.ToLower(tlsValue) == "preferred" { | ||
// Do nothing here | ||
return nil | ||
} else if cfg.cert != "" { | ||
certBytes, err := ioutil.ReadFile(cfg.cert) | ||
if err != nil { | ||
return err | ||
} | ||
caCertPool := x509.NewCertPool() | ||
if ok := caCertPool.AppendCertsFromPEM(certBytes); !ok { | ||
return err | ||
} | ||
|
||
tlsConfig := tls.Config{} | ||
tlsConfig.RootCAs = caCertPool | ||
if tlsValue == "verify_identity" { | ||
tlsConfig.ServerName = strings.Split(cfg.config.Addr,":")[0] | ||
} | ||
|
||
err = mysql.RegisterTLSConfig(tlsValue, &tlsConfig) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
} else { | ||
return fmt.Errorf("sql ca file is not provided") | ||
} | ||
return nil | ||
} | ||
|
||
func readBool(input string) (value bool, valid bool) { | ||
switch input { | ||
case "1", "true", "TRUE", "True": | ||
return true, true | ||
case "0", "false", "FALSE", "False": | ||
return false, true | ||
} | ||
return | ||
} | ||
|
||
func detectDirver(dbUrl string)(driver string) { | ||
if strings.Contains(dbUrl, "postgres"){ | ||
return PostgresDriverName | ||
} else { | ||
return MysqlDriverName | ||
} | ||
} | ||
|
||
// parseMySQLURL can parse the query parameters and remove invalid 'sslrootcert', it return mysql.Config and the cert file. | ||
func parseMySQLURL(dbUrl string)( *MySQLConfig, error) { | ||
var caCert string | ||
var tlsValue string | ||
if strings.Contains(dbUrl,"?"){ | ||
u, err := url.ParseQuery(strings.Split(dbUrl,"?")[1]) | ||
if err != nil { | ||
return nil, err | ||
} | ||
urlParam := url.Values{} | ||
for k, v := range u { | ||
if k == "sslrootcert" { | ||
caCert = v[0] | ||
continue | ||
} | ||
if k == "tls" { | ||
tlsValue = v[0] | ||
continue | ||
} | ||
urlParam.Add(k, v[0]) | ||
} | ||
dbUrl = fmt.Sprintf("%s?%s",strings.Split(dbUrl,"?")[0], urlParam.Encode()) | ||
} | ||
|
||
config, err := mysql.ParseDSN(dbUrl) | ||
if err != nil { | ||
return nil, err | ||
} | ||
config.ParseTime = true | ||
|
||
if tlsValue != "" { | ||
config.TLSConfig = tlsValue | ||
} | ||
|
||
return &MySQLConfig{ | ||
config: config, | ||
cert: caCert, | ||
}, nil | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package db_test | ||
|
||
import ( | ||
. "autoscaler/db" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
var _ = Describe("Helper", func() { | ||
var ( | ||
dbUrl string | ||
err error | ||
database *Database | ||
certPath string | ||
) | ||
|
||
Describe("GetConnection", func() { | ||
|
||
JustBeforeEach(func() { | ||
database, err = GetConnection(dbUrl) | ||
}) | ||
Context("when mysql query parameters are provided", func() { | ||
BeforeEach(func() { | ||
dbUrl="root@tcp(localhost:3306)/autoscaler?tls=preferred" | ||
}) | ||
It("returns mysql database object", func() { | ||
Expect(err).NotTo(HaveOccurred()) | ||
Expect(database).To(Equal(&Database{ | ||
DriverName: "mysql", | ||
DSN: "root@tcp(localhost:3306)/autoscaler?parseTime=true&tls=preferred", | ||
})) | ||
}) | ||
}) | ||
|
||
Context("when mysql query parameters are not provided", func() { | ||
BeforeEach(func() { | ||
dbUrl="root@tcp(localhost:3306)/autoscaler" | ||
}) | ||
It("returns mysql database object", func() { | ||
Expect(err).NotTo(HaveOccurred()) | ||
Expect(database).To(Equal(&Database{ | ||
DriverName: "mysql", | ||
DSN: "root@tcp(localhost:3306)/autoscaler?parseTime=true", | ||
})) | ||
}) | ||
|
||
}) | ||
|
||
Context("when need to verify mysql server, cert is provided ", func() { | ||
BeforeEach(func() { | ||
certPath="../../../test-certs/api.crt" | ||
dbUrl="root@tcp(localhost:3306)/autoscaler?tls=verify-ca&sslrootcert="+certPath | ||
}) | ||
It("returns mysql database connection", func() { | ||
Expect(err).NotTo(HaveOccurred()) | ||
Expect(database).To(Equal(&Database{ | ||
DriverName: "mysql", | ||
DSN: "root@tcp(localhost:3306)/autoscaler?parseTime=true&tls=verify-ca", | ||
})) | ||
}) | ||
}) | ||
|
||
Context("when need to verify mysql server, cert is not provided ", func() { | ||
BeforeEach(func() { | ||
dbUrl="root@tcp(localhost:3306)/autoscaler?tls=verify-ca" | ||
}) | ||
It("should error", func() { | ||
Expect(err).To(HaveOccurred()) | ||
Expect(err.Error()).To(ContainSubstring("sql ca file is not provided")) | ||
}) | ||
}) | ||
|
||
Context("when postgres dburl is provided", func() { | ||
BeforeEach(func() { | ||
dbUrl="postgres://postgres:password@localhost:5432/autoscaler?sslmode=disable" | ||
}) | ||
It("returns postgres database object", func() { | ||
Expect(err).NotTo(HaveOccurred()) | ||
Expect(database).To(Equal(&Database{ | ||
DriverName: "postgres", | ||
DSN: "postgres://postgres:password@localhost:5432/autoscaler?sslmode=disable", | ||
})) | ||
}) | ||
}) | ||
}) | ||
}) |
Oops, something went wrong.