Skip to content

Commit

Permalink
Migrate to github.com/go-sql-driver/mysql
Browse files Browse the repository at this point in the history
This is a better-maintained driver implementation that has TLS support.
  • Loading branch information
bonifaido authored and apparentlymart committed Oct 20, 2017
1 parent a9a7b10 commit 8e3f7a9
Show file tree
Hide file tree
Showing 32 changed files with 6,047 additions and 92 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,15 @@ In order to run the full suite of Acceptance tests, run `make testacc`.
```sh
$ make testacc
```

If you want to run the Acceptance tests on your own machine with a MySQL in Docker:

```bash
$ docker run --rm --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d -p 3306:3306 mysql:5.7
$ # wait for a few seconds to let MySQL stand up, check the logs with: docker logs -f some-mysql
$ export MYSQL_USERNAME=root
$ export MYSQL_ENDPOINT=localhost:3306
$ export MYSQL_PASSWORD=my-secret-pw
$ make testacc
$ docker rm -f some-mysql
```
31 changes: 15 additions & 16 deletions mysql/provider.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package mysql

import (
"database/sql"
"fmt"
"strings"

_ "github.com/go-sql-driver/mysql"
"github.com/hashicorp/go-version"
mysqlc "github.com/ziutek/mymysql/mysql"
mysqlts "github.com/ziutek/mymysql/thrsafe"

"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
)

type providerConfiguration struct {
Conn mysqlc.Conn
DB *sql.DB
ServerVersion *version.Version
}

Expand Down Expand Up @@ -76,23 +76,20 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
proto = "unix"
}

// mysqlts is the thread-safe implementation of mymysql, so we can
// safely re-use the same connection between multiple parallel
// database/sql is the thread-safe by default, so we can
// safely re-use the same handle between multiple parallel
// operations.
conn := mysqlts.New(proto, "", endpoint, username, password)

err := conn.Connect()
if err != nil {
return nil, err
}
dataSourceName := fmt.Sprintf("%s:%s@%s(%s)/", username, password, proto, endpoint)
db, err := sql.Open("mysql", dataSourceName)

ver, err := serverVersion(conn)
ver, err := serverVersion(db)
if err != nil {
return nil, err
}

return &providerConfiguration{
Conn: conn,
DB: db,
ServerVersion: ver,
}, nil
}
Expand All @@ -103,14 +100,16 @@ func quoteIdentifier(in string) string {
return fmt.Sprintf("`%s`", identQuoteReplacer.Replace(in))
}

func serverVersion(conn mysqlc.Conn) (*version.Version, error) {
rows, _, err := conn.Query("SELECT VERSION()")
func serverVersion(db *sql.DB) (*version.Version, error) {
rows, err := db.Query("SELECT VERSION()")
if err != nil {
return nil, err
}
if len(rows) == 0 {
if !rows.Next() {
return nil, fmt.Errorf("SELECT VERSION() returned an empty set")
}

return version.NewVersion(rows[0].Str(0))
var versionString string
rows.Scan(&versionString)
return version.NewVersion(versionString)
}
47 changes: 24 additions & 23 deletions mysql/resource_database.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package mysql

import (
"database/sql"
"fmt"
"log"
"strings"

mysqlc "github.com/ziutek/mymysql/mysql"
"github.com/go-sql-driver/mysql"

"github.com/hashicorp/terraform/helper/schema"
)

const defaultCharacterSetKeyword = "CHARACTER SET "
const defaultCollateKeyword = "COLLATE "
const unknownDatabaseErrCode = 1049

func resourceDatabase() *schema.Resource {
return &schema.Resource{
Expand Down Expand Up @@ -43,12 +45,12 @@ func resourceDatabase() *schema.Resource {
}

func CreateDatabase(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*providerConfiguration).Conn
db := meta.(*providerConfiguration).DB

stmtSQL := databaseConfigSQL("CREATE", d)
log.Println("Executing statement:", stmtSQL)

_, _, err := conn.Query(stmtSQL)
_, err := db.Exec(stmtSQL)
if err != nil {
return err
}
Expand All @@ -59,12 +61,12 @@ func CreateDatabase(d *schema.ResourceData, meta interface{}) error {
}

func UpdateDatabase(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*providerConfiguration).Conn
db := meta.(*providerConfiguration).DB

stmtSQL := databaseConfigSQL("ALTER", d)
log.Println("Executing statement:", stmtSQL)

_, _, err := conn.Query(stmtSQL)
_, err := db.Exec(stmtSQL)
if err != nil {
return err
}
Expand All @@ -73,7 +75,7 @@ func UpdateDatabase(d *schema.ResourceData, meta interface{}) error {
}

func ReadDatabase(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*providerConfiguration).Conn
db := meta.(*providerConfiguration).DB

// This is kinda flimsy-feeling, since it depends on the formatting
// of the SHOW CREATE DATABASE output... but this data doesn't seem
Expand All @@ -84,37 +86,36 @@ func ReadDatabase(d *schema.ResourceData, meta interface{}) error {
stmtSQL := "SHOW CREATE DATABASE " + quoteIdentifier(name)

log.Println("Executing query:", stmtSQL)
rows, _, err := conn.Query(stmtSQL)
var createSQL, _database string
err := db.QueryRow(stmtSQL).Scan(&_database, &createSQL)
if err != nil {
if mysqlErr, ok := err.(*mysqlc.Error); ok {
if mysqlErr.Code == mysqlc.ER_BAD_DB_ERROR {
if mysqlErr, ok := err.(*mysql.MySQLError); ok {
if mysqlErr.Number == unknownDatabaseErrCode {
d.SetId("")
return nil
}
}
return err
return fmt.Errorf("Error during show create database: %s", err)
}

row := rows[0]
createSQL := string(row[1].([]byte))

defaultCharset := extractIdentAfter(createSQL, defaultCharacterSetKeyword)
defaultCollation := extractIdentAfter(createSQL, defaultCollateKeyword)

if defaultCollation == "" && defaultCharset != "" {
// MySQL doesn't return the collation if it's the default one for
// the charset, so if we don't have a collation we need to go
// hunt for the default.
stmtSQL := "SHOW COLLATION WHERE `Charset` = '%s' AND `Default` = 'Yes'"
rows, _, err := conn.Query(stmtSQL, defaultCharset)
stmtSQL := "SHOW COLLATION WHERE `Charset` = ? AND `Default` = 'Yes'"
var defaultCollation string
var empty interface{}
err := db.QueryRow(stmtSQL, defaultCharset).Scan(&defaultCollation, &empty, &empty, &empty, &empty, &empty)
if err != nil {
return fmt.Errorf("Error getting default charset: %s", err)
}
if len(rows) == 0 {
return fmt.Errorf("Charset %s has no default collation", defaultCharset)
if err == sql.ErrNoRows {
return fmt.Errorf("Charset %s has no default collation", defaultCharset)
}
return fmt.Errorf("Error getting default charset: %s, %s", err, defaultCharset)
}
row := rows[0]
defaultCollation = string(row[0].([]byte))
return err
}

d.Set("default_character_set", defaultCharset)
Expand All @@ -124,13 +125,13 @@ func ReadDatabase(d *schema.ResourceData, meta interface{}) error {
}

func DeleteDatabase(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*providerConfiguration).Conn
db := meta.(*providerConfiguration).DB

name := d.Id()
stmtSQL := "DROP DATABASE " + quoteIdentifier(name)
log.Println("Executing statement:", stmtSQL)

_, _, err := conn.Query(stmtSQL)
_, err := db.Exec(stmtSQL)
if err == nil {
d.SetId("")
}
Expand Down
32 changes: 20 additions & 12 deletions mysql/resource_database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"strings"
"testing"

mysqlc "github.com/ziutek/mymysql/mysql"
"github.com/go-sql-driver/mysql"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
Expand Down Expand Up @@ -39,17 +39,19 @@ func testAccDatabaseCheck(rn string, name *string) resource.TestCheckFunc {
return fmt.Errorf("database id not set")
}

conn := testAccProvider.Meta().(*providerConfiguration).Conn
rows, _, err := conn.Query("SHOW CREATE DATABASE terraform_acceptance_test")
db := testAccProvider.Meta().(*providerConfiguration).DB
rows, err := db.Query("SHOW CREATE DATABASE terraform_acceptance_test")
if err != nil {
return fmt.Errorf("error reading database: %s", err)
}
if len(rows) != 1 {
return fmt.Errorf("expected 1 row reading database but got %d", len(rows))
}
defer rows.Close()

row := rows[0]
createSQL := string(row[1].([]byte))
rows.Next()
var _name, createSQL string
err = rows.Scan(&_name, &createSQL)
if err != nil {
return fmt.Errorf("error scanning create statement: %s", err)
}

if strings.Index(createSQL, "CHARACTER SET utf8") == -1 {
return fmt.Errorf("database default charset isn't utf8")
Expand All @@ -58,6 +60,10 @@ func testAccDatabaseCheck(rn string, name *string) resource.TestCheckFunc {
return fmt.Errorf("database default collation isn't utf8_bin")
}

if rows.Next() {
return fmt.Errorf("expected 1 row reading database, but got more")
}

*name = rs.Primary.ID

return nil
Expand All @@ -66,14 +72,16 @@ func testAccDatabaseCheck(rn string, name *string) resource.TestCheckFunc {

func testAccDatabaseCheckDestroy(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
conn := testAccProvider.Meta().(*providerConfiguration).Conn
db := testAccProvider.Meta().(*providerConfiguration).DB

_, _, err := conn.Query("SHOW CREATE DATABASE terraform_acceptance_test")
var name, createSQL string
err := db.QueryRow("SHOW CREATE DATABASE terraform_acceptance_test").Scan(&name, &createSQL)
if err == nil {
return fmt.Errorf("database still exists after destroy")
}
if mysqlErr, ok := err.(*mysqlc.Error); ok {
if mysqlErr.Code == mysqlc.ER_BAD_DB_ERROR {

if mysqlErr, ok := err.(*mysql.MySQLError); ok {
if mysqlErr.Number == unknownDatabaseErrCode {
return nil
}
}
Expand Down
18 changes: 11 additions & 7 deletions mysql/resource_grant.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/hashicorp/terraform/helper/schema"
)

const nonexistingGrantErrCode = 1141

func resourceGrant() *schema.Resource {
return &schema.Resource{
Create: CreateGrant,
Expand Down Expand Up @@ -54,7 +56,7 @@ func resourceGrant() *schema.Resource {
}

func CreateGrant(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*providerConfiguration).Conn
db := meta.(*providerConfiguration).DB

// create a comma-delimited string of privileges
var privileges string
Expand All @@ -76,7 +78,7 @@ func CreateGrant(d *schema.ResourceData, meta interface{}) error {
}

log.Println("Executing statement:", stmtSQL)
_, _, err := conn.Query(stmtSQL)
_, err := db.Exec(stmtSQL)
if err != nil {
return err
}
Expand All @@ -88,31 +90,33 @@ func CreateGrant(d *schema.ResourceData, meta interface{}) error {
}

func ReadGrant(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*providerConfiguration).Conn
db := meta.(*providerConfiguration).DB

stmtSQL := fmt.Sprintf("SHOW GRANTS FOR '%s'@'%s'",
d.Get("user").(string),
d.Get("host").(string))

log.Println("Executing statement:", stmtSQL)

_, _, err := conn.Query(stmtSQL)
rows, err := db.Query(stmtSQL)
if err != nil {
d.SetId("")
} else {
rows.Close()
}
return nil
}

func DeleteGrant(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*providerConfiguration).Conn
db := meta.(*providerConfiguration).DB

stmtSQL := fmt.Sprintf("REVOKE GRANT OPTION ON %s.* FROM '%s'@'%s'",
d.Get("database").(string),
d.Get("user").(string),
d.Get("host").(string))

log.Println("Executing statement:", stmtSQL)
_, _, err := conn.Query(stmtSQL)
_, err := db.Query(stmtSQL)
if err != nil {
return err
}
Expand All @@ -123,7 +127,7 @@ func DeleteGrant(d *schema.ResourceData, meta interface{}) error {
d.Get("host").(string))

log.Println("Executing statement:", stmtSQL)
_, _, err = conn.Query(stmtSQL)
_, err = db.Exec(stmtSQL)
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit 8e3f7a9

Please sign in to comment.