Skip to content

Commit

Permalink
Readd MySQL 5.6 compatiblity, speedup execution
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter Junos committed Jul 1, 2022
1 parent ac51588 commit 21e6241
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 68 deletions.
11 changes: 7 additions & 4 deletions mysql/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type MySQLConfiguration struct {
MaxConnLifetime time.Duration
MaxOpenConns int
ConnectRetryTimeoutSec time.Duration
Version *version.Version
}

var (
Expand Down Expand Up @@ -198,24 +199,26 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
}

mysqlConf.Db = db
if err := afterConnect(d, db); err != nil {
if err := afterConnect(mysqlConf, db); err != nil {
return nil, fmt.Errorf("Failed running after connect command: %v", err)
}

return mysqlConf, nil
}

func afterConnect(d *schema.ResourceData, db *sql.DB) error {
func afterConnect(mysqlConf *MySQLConfiguration, db *sql.DB) error {
// Set up env so that we won't create users randomly.
currentVersion, err := serverVersion(db)
if err != nil {
return fmt.Errorf("Failed getting server version: %v", err)
}

mysqlConf.Version = currentVersion

versionMinInclusive, _ := version.NewVersion("5.7.5")
versionMaxExclusive, _ := version.NewVersion("8.0.0")
if currentVersion.GreaterThanOrEqual(versionMinInclusive) &&
currentVersion.LessThan(versionMaxExclusive) {
if mysqlConf.Version.GreaterThanOrEqual(versionMinInclusive) &&
mysqlConf.Version.LessThan(versionMaxExclusive) {
// CONCAT and setting works even if there is no value.
_, err := db.Exec(`SET SESSION sql_mode=CONCAT(@@sql_mode, ',NO_AUTO_CREATE_USER')`)
if err != nil {
Expand Down
9 changes: 3 additions & 6 deletions mysql/resource_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ func UpdateDatabase(d *schema.ResourceData, meta interface{}) error {
}

func ReadDatabase(d *schema.ResourceData, meta interface{}) error {
db := meta.(*MySQLConfiguration).Db
mysqlConf := meta.(*MySQLConfiguration)
db := mysqlConf.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 Down Expand Up @@ -111,10 +112,6 @@ func ReadDatabase(d *schema.ResourceData, meta interface{}) error {
var empty interface{}

requiredVersion, _ := version.NewVersion("8.0.0")
currentVersion, err := serverVersion(db)
if err != nil {
return err
}

serverVersionString, err := serverVersionString(db)
if err != nil {
Expand All @@ -123,7 +120,7 @@ func ReadDatabase(d *schema.ResourceData, meta interface{}) error {

// MySQL 8 returns more data in a row.
var res error
if !strings.Contains(serverVersionString, "MariaDB") && currentVersion.GreaterThan(requiredVersion) {
if !strings.Contains(serverVersionString, "MariaDB") && mysqlConf.Version.GreaterThan(requiredVersion) {
res = db.QueryRow(stmtSQL, defaultCharset).Scan(&defaultCollation, &empty, &empty, &empty, &empty, &empty, &empty)
} else {
res = db.QueryRow(stmtSQL, defaultCharset).Scan(&defaultCollation, &empty, &empty, &empty, &empty, &empty)
Expand Down
15 changes: 6 additions & 9 deletions mysql/resource_grant.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,8 @@ func userOrRole(user string, host string, role string, hasRoles bool) (string, b
}
}

func supportsRoles(db *sql.DB) (bool, error) {
currentVersion, err := serverVersion(db)
if err != nil {
return false, err
}
func supportsRoles(meta interface{}) (bool, error) {
currentVersion := meta.(*MySQLConfiguration).Version

requiredVersion, _ := version.NewVersion("8.0.0")
hasRoles := currentVersion.GreaterThan(requiredVersion)
Expand All @@ -160,7 +157,7 @@ func supportsRoles(db *sql.DB) (bool, error) {
func CreateGrant(d *schema.ResourceData, meta interface{}) error {
db := meta.(*MySQLConfiguration).Db

hasRoles, err := supportsRoles(db)
hasRoles, err := supportsRoles(meta)
if err != nil {
return err
}
Expand Down Expand Up @@ -263,7 +260,7 @@ func CreateGrant(d *schema.ResourceData, meta interface{}) error {
func ReadGrant(d *schema.ResourceData, meta interface{}) error {
db := meta.(*MySQLConfiguration).Db

hasRoles, err := supportsRoles(db)
hasRoles, err := supportsRoles(meta)
if err != nil {
return err
}
Expand Down Expand Up @@ -323,7 +320,7 @@ func ReadGrant(d *schema.ResourceData, meta interface{}) error {
func UpdateGrant(d *schema.ResourceData, meta interface{}) error {
db := meta.(*MySQLConfiguration).Db

hasRoles, err := supportsRoles(db)
hasRoles, err := supportsRoles(meta)

if err != nil {
return err
Expand Down Expand Up @@ -402,7 +399,7 @@ func DeleteGrant(d *schema.ResourceData, meta interface{}) error {

table := formatTableName(d.Get("table").(string))

hasRoles, err := supportsRoles(db)
hasRoles, err := supportsRoles(meta)
if err != nil {
return err
}
Expand Down
94 changes: 52 additions & 42 deletions mysql/resource_user.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package mysql

import (
"database/sql"
"fmt"
"log"
"regexp"
Expand Down Expand Up @@ -69,7 +68,6 @@ func resourceUser() *schema.Resource {
"tls_option": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Default: "NONE",
},
},
Expand Down Expand Up @@ -122,17 +120,13 @@ func CreateUser(d *schema.ResourceData, meta interface{}) error {
}

requiredVersion, _ := version.NewVersion("5.7.0")
currentVersion, err := serverVersion(db)
if err != nil {
return err
}

if currentVersion.GreaterThan(requiredVersion) && d.Get("tls_option").(string) != "" {
if meta.(*MySQLConfiguration).Version.GreaterThan(requiredVersion) && d.Get("tls_option").(string) != "" {
stmtSQL += fmt.Sprintf(" REQUIRE %s", d.Get("tls_option").(string))
}

log.Println("Executing statement:", stmtSQL)
_, err = db.Exec(stmtSQL)
_, err := db.Exec(stmtSQL)
if err != nil {
return err
}
Expand All @@ -143,29 +137,24 @@ func CreateUser(d *schema.ResourceData, meta interface{}) error {
return nil
}

func getSetPasswordStatement(db *sql.DB) (string, error) {
func getSetPasswordStatement(meta interface{}) (string, error) {
/* ALTER USER syntax introduced in MySQL 5.7.6 deprecates SET PASSWORD (GH-8230) */
serverVersion, err := serverVersion(db)
if err != nil {
return "", fmt.Errorf("Could not determine server version: %s", err)
}

ver, _ := version.NewVersion("5.7.6")
if serverVersion.LessThan(ver) {
if meta.(*MySQLConfiguration).Version.LessThan(ver) {
return "SET PASSWORD FOR ?@? = PASSWORD(?)", nil
} else {
return "ALTER USER ?@? IDENTIFIED BY ?", nil
}
}

func UpdateUser(d *schema.ResourceData, meta interface{}) error {
db := meta.(*MySQLConfiguration).Db
mysqlConf := meta.(*MySQLConfiguration)
db := mysqlConf.Db

var auth string
if v, ok := d.GetOk("auth_plugin"); ok {
auth = v.(string)
}

if len(auth) > 0 {
if d.HasChange("tls_option") || d.HasChange("auth_plugin") || d.HasChange("auth_string_hashed") {
var stmtSQL string
Expand Down Expand Up @@ -201,7 +190,7 @@ func UpdateUser(d *schema.ResourceData, meta interface{}) error {
}

if newpw != nil {
stmtSQL, err := getSetPasswordStatement(db)
stmtSQL, err := getSetPasswordStatement(meta)
if err != nil {
return err
}
Expand All @@ -217,12 +206,7 @@ func UpdateUser(d *schema.ResourceData, meta interface{}) error {
}

requiredVersion, _ := version.NewVersion("5.7.0")
currentVersion, err := serverVersion(db)
if err != nil {
return err
}

if d.HasChange("tls_option") && currentVersion.GreaterThan(requiredVersion) {
if d.HasChange("tls_option") && mysqlConf.Version.GreaterThan(requiredVersion) {
var stmtSQL string

stmtSQL = fmt.Sprintf("ALTER USER '%s'@'%s' REQUIRE %s",
Expand All @@ -242,27 +226,53 @@ func UpdateUser(d *schema.ResourceData, meta interface{}) error {

func ReadUser(d *schema.ResourceData, meta interface{}) error {
db := meta.(*MySQLConfiguration).Db
stmt := "SHOW CREATE USER ?@?"
currentVersion := meta.(*MySQLConfiguration).Version
requiredVersion, _ := version.NewVersion("5.7.0")
if currentVersion.GreaterThan(requiredVersion) {
stmt := "SHOW CREATE USER ?@?"

var createUserStmt string
err := db.QueryRow(stmt, d.Get("user").(string), d.Get("host").(string)).Scan(&createUserStmt)
if err != nil {
if mysqlErrorNumber(err) == unknownUserErrCode {
d.SetId("")
return nil
var createUserStmt string
err := db.QueryRow(stmt, d.Get("user").(string), d.Get("host").(string)).Scan(&createUserStmt)
if err != nil {
if mysqlErrorNumber(err) == unknownUserErrCode {
d.SetId("")
return nil
}
return err
}
return err
}
// CREATE USER 'some_app'@'%' IDENTIFIED WITH 'mysql_native_password' AS '*0something' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK
re := regexp.MustCompile(`^CREATE USER '([^']*)'@'([^']*)' IDENTIFIED WITH '([^']*)' (?:AS '([^']*)' )?REQUIRE ([^ ]*)`)
if m := re.FindStringSubmatch(createUserStmt); len(m) == 6 {
d.Set("user", m[1])
d.Set("host", m[2])
d.Set("auth_plugin", m[3])
d.Set("auth_string_hashed", m[4])
d.Set("tls_option", m[5])

// Examples of create user:
// CREATE USER 'some_app'@'%' IDENTIFIED WITH 'mysql_native_password' AS '*0something' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK
// CREATE USER `jdoe-tf-test-47`@`example.com` IDENTIFIED WITH 'caching_sha2_password' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK PASSWORD HISTORY DEFAULT PASSWORD REUSE INTERVAL DEFAULT PASSWORD REQUIRE CURRENT DEFAULT
// CREATE USER `jdoe`@`example.com` IDENTIFIED WITH 'caching_sha2_password' AS '$A$005$i`xay#fG/\' TrbkNA82' REQUIRE NONE PASSWORD
re := regexp.MustCompile("^CREATE USER ['`]([^'`]*)['`]@['`]([^'`]*)['`] IDENTIFIED WITH ['`]([^'`]*)['`] (?:AS '((?:.*?[^\\\\])?)' )?REQUIRE ([^ ]*)")
if m := re.FindStringSubmatch(createUserStmt); len(m) == 6 {
d.Set("user", m[1])
d.Set("host", m[2])
d.Set("auth_plugin", m[3])
d.Set("auth_string_hashed", m[4])
d.Set("tls_option", m[5])
} else {
return fmt.Errorf("Create user couldn't be parsed - it is %s", createUserStmt)
}
return nil
} else {
return fmt.Errorf("Create user couldn't be parsed - it is %s", createUserStmt)
// Worse user detection, only for compat with MySQL 5.6
stmtSQL := fmt.Sprintf("SELECT USER FROM mysql.user WHERE USER='%s'",
d.Get("user").(string))

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

rows, err := db.Query(stmtSQL)
if err != nil {
return err
}
defer rows.Close()

if !rows.Next() && rows.Err() == nil {
d.SetId("")
return rows.Err()
}
}
return nil
}
Expand Down
9 changes: 2 additions & 7 deletions mysql/resource_user_password.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func SetUserPassword(d *schema.ResourceData, meta interface{}) error {
d.Set("plaintext_password", password)
}

stmtSQL, err := getSetPasswordStatement(db)
stmtSQL, err := getSetPasswordStatement(meta)
if err != nil {
return err
}
Expand All @@ -68,12 +68,7 @@ func SetUserPassword(d *schema.ResourceData, meta interface{}) error {
}

func canReadPassword(meta interface{}) (bool, error) {
db := meta.(*MySQLConfiguration).Db
serverVersion, err := serverVersion(db)
if err != nil {
return false, fmt.Errorf("Could not determine server version: %s", err)
}

serverVersion := meta.(*MySQLConfiguration).Version
ver, _ := version.NewVersion("8.0.0")
return serverVersion.LessThan(ver), nil
}
Expand Down

0 comments on commit 21e6241

Please sign in to comment.