diff --git a/.gitignore b/.gitignore index 5982d2c64..1b116c582 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ example.tf terraform.tfplan terraform.tfstate +terraform-provider-mysql bin/ modules-dev/ /pkg/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 89bd07592..e994c8463 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,19 +1,23 @@ -## 1.1.1 (Unreleased) +## 1.5.0 (Unreleased) -IMPROVEMENTS: +BUG FIXES: -* `resource/user`: Added the `tls_option` attribute, which allows to restrict - the MySQL users to a specific MySQL-TLS-Encryption. ([#26](https://github.com/terraform-providers/terraform-provider-mysql/issues/40)) +* Lazily connect to MySQL servers. ([#43](https://github.com/terraform-providers/terraform-provider-mysql/issues/43)) +* Add retries to MySQL server connection logic. ([#43](https://github.com/terraform-providers/terraform-provider-mysql/issues/43)) +* Migrated to Go modules for dependencies and `vendor/` management. -* `resource/gant`: Added the `tls_option` attribute, which allows to restrict - the MySQL grant to a specific MySQL-TLS-Encryption. ([#26](https://github.com/terraform-providers/terraform-provider-mysql/issues/40)) +IMPROVEMENTS: + +* Provider now has a `tls` option that configures TSL for server connections. ([#43](https://github.com/terraform-providers/terraform-provider-mysql/issues/43)) +* `r/mysql_user`: Added the `tls_option` attribute, which allows to restrict the MySQL users to a specific MySQL-TLS-Encryption. ([#26](https://github.com/terraform-providers/terraform-provider-mysql/issues/40)) +* `r/mysql_grant`: Added the `tls_option` attribute, which allows to restrict the MySQL grant to a specific MySQL-TLS-Encryption. ([#26](https://github.com/terraform-providers/terraform-provider-mysql/issues/40)) +* `r/mysql_grant`: Added a `table` argument that allows `GRANT` statements to be scoped to a single table. ## 1.1.0 (March 28, 2018) IMPROVEMENTS: -* `resource/user`: Added the `auth_plugin` attribute, which allows for the use - of authentication plugins when creating MySQL users. ([#26](https://github.com/terraform-providers/terraform-provider-mysql/issues/26)) +* `resource/user`: Added the `auth_plugin` attribute, which allows for the use of authentication plugins when creating MySQL users. ([#26](https://github.com/terraform-providers/terraform-provider-mysql/issues/26)) ## 1.0.1 (January 03, 2018) @@ -25,9 +29,9 @@ BUG FIXES: UPGRADE NOTES: -* This provider is now using a different underlying library to access MySQL (See [[#16](https://github.com/terraform-providers/terraform-provider-mysql/issues/16)]). This should be a drop-in replacement for all of the functionality exposed by this provider, but just in case it is suggested to test cautiously after upgrading (review plans before applying, etc) in case of any edge-cases in interactions with specific versions of MySQL. +* This provider is now using a different underlying library to access MySQL (See [#16](https://github.com/terraform-providers/terraform-provider-mysql/issues/16)). This should be a drop-in replacement for all of the functionality exposed by this provider, but just in case it is suggested to test cautiously after upgrading (review plans before applying, etc) in case of any edge-cases in interactions with specific versions of MySQL. -ENHANCEMENTS: +IMPROVEMENTS: * `mysql_user` now has a `plaintext_password` argument which stores its value in state as an _unsalted_ hash. This deprecates `password`, which stores its value in the state in cleartext. Since the hash is unsalted, some care is still warranted to secure the state, and a strong password should be used to reduce the chance of a successful brute-force attack on the hash. ([#9](https://github.com/terraform-providers/terraform-provider-mysql/issues/9)) diff --git a/mysql/provider.go b/mysql/provider.go index 2b8a017c1..f9458c4fd 100644 --- a/mysql/provider.go +++ b/mysql/provider.go @@ -4,17 +4,18 @@ import ( "database/sql" "fmt" "strings" + "time" - _ "github.com/go-sql-driver/mysql" + "github.com/go-sql-driver/mysql" "github.com/hashicorp/go-version" + "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/terraform" ) -type providerConfiguration struct { - DB *sql.DB - ServerVersion *version.Version +type MySQLConfiguration struct { + Config *mysql.Config } func Provider() terraform.ResourceProvider { @@ -38,14 +39,6 @@ func Provider() terraform.ResourceProvider { Type: schema.TypeString, Required: true, DefaultFunc: schema.EnvDefaultFunc("MYSQL_USERNAME", nil), - ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - if value == "" { - errors = append(errors, fmt.Errorf("Username must not be an empty string")) - } - - return - }, }, "password": &schema.Schema{ @@ -53,6 +46,19 @@ func Provider() terraform.ResourceProvider { Optional: true, DefaultFunc: schema.EnvDefaultFunc("MYSQL_PASSWORD", nil), }, + + "tls": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DefaultFunc: schema.EnvDefaultFunc("MYSQL_TLS_CONFIG", "false"), + /* + ValidateFunc: validation.StringInSlice([]string{ + "true", + "false", + "skip-verify", + }, false), + */ + }, }, ResourcesMap: map[string]*schema.Resource{ @@ -67,8 +73,6 @@ func Provider() terraform.ResourceProvider { func providerConfigure(d *schema.ResourceData) (interface{}, error) { - var username = d.Get("username").(string) - var password = d.Get("password").(string) var endpoint = d.Get("endpoint").(string) proto := "tcp" @@ -76,21 +80,16 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) { proto = "unix" } - // database/sql is the thread-safe by default, so we can - // safely re-use the same handle between multiple parallel - // operations. - - dataSourceName := fmt.Sprintf("%s:%s@%s(%s)/", username, password, proto, endpoint) - db, err := sql.Open("mysql", dataSourceName) - - ver, err := serverVersion(db) - if err != nil { - return nil, err + conf := mysql.Config{ + User: d.Get("username").(string), + Passwd: d.Get("password").(string), + Net: proto, + Addr: endpoint, + TLSConfig: d.Get("tls").(string), } - return &providerConfiguration{ - DB: db, - ServerVersion: ver, + return &MySQLConfiguration{ + Config: &conf, }, nil } @@ -101,15 +100,44 @@ func quoteIdentifier(in string) string { } func serverVersion(db *sql.DB) (*version.Version, error) { - rows, err := db.Query("SELECT VERSION()") + var versionString string + err := db.QueryRow("SELECT @@GLOBAL.innodb_version").Scan(&versionString) if err != nil { return nil, err } - if !rows.Next() { - return nil, fmt.Errorf("SELECT VERSION() returned an empty set") - } - var versionString string - rows.Scan(&versionString) return version.NewVersion(versionString) } + +func connectToMySQL(conf *mysql.Config) (*sql.DB, error) { + dsn := conf.FormatDSN() + var db *sql.DB + var err error + + // When provisioning a database server there can often be a lag between + // when Terraform thinks it's available and when it is actually available. + // This is particularly acute when provisioning a server and then immediately + // trying to provision a database on it. + retryError := resource.Retry(5*time.Minute, func() *resource.RetryError { + db, err = sql.Open("mysql", dsn) + if err != nil { + return resource.RetryableError(err) + } + + // The Go SDK for MySQL doesn't actually connect until a query is ran. + // This forces a simple query to run, which runs a connect, which lets + // the retry logic do its thing. + _, err = serverVersion(db) + if err != nil { + return resource.RetryableError(err) + } + + return nil + }) + + if retryError != nil { + return nil, fmt.Errorf("Could not connect to server: %s", retryError) + } + + return db, nil +} diff --git a/mysql/resource_database.go b/mysql/resource_database.go index ec2cacf08..89f4d37cf 100644 --- a/mysql/resource_database.go +++ b/mysql/resource_database.go @@ -21,7 +21,9 @@ func resourceDatabase() *schema.Resource { Update: UpdateDatabase, Read: ReadDatabase, Delete: DeleteDatabase, - + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "name": &schema.Schema{ Type: schema.TypeString, @@ -45,37 +47,46 @@ func resourceDatabase() *schema.Resource { } func CreateDatabase(d *schema.ResourceData, meta interface{}) error { - db := meta.(*providerConfiguration).DB + db, err := connectToMySQL(meta.(*MySQLConfiguration).Config) + if err != nil { + return err + } stmtSQL := databaseConfigSQL("CREATE", d) log.Println("Executing statement:", stmtSQL) - _, err := db.Exec(stmtSQL) + _, err = db.Exec(stmtSQL) if err != nil { return err } d.SetId(d.Get("name").(string)) - return nil + return ReadDatabase(d, meta) } func UpdateDatabase(d *schema.ResourceData, meta interface{}) error { - db := meta.(*providerConfiguration).DB + db, err := connectToMySQL(meta.(*MySQLConfiguration).Config) + if err != nil { + return err + } stmtSQL := databaseConfigSQL("ALTER", d) log.Println("Executing statement:", stmtSQL) - _, err := db.Exec(stmtSQL) + _, err = db.Exec(stmtSQL) if err != nil { return err } - return nil + return ReadDatabase(d, meta) } func ReadDatabase(d *schema.ResourceData, meta interface{}) error { - db := meta.(*providerConfiguration).DB + db, err := connectToMySQL(meta.(*MySQLConfiguration).Config) + if err != nil { + return err + } // This is kinda flimsy-feeling, since it depends on the formatting // of the SHOW CREATE DATABASE output... but this data doesn't seem @@ -87,7 +98,7 @@ func ReadDatabase(d *schema.ResourceData, meta interface{}) error { log.Println("Executing query:", stmtSQL) var createSQL, _database string - err := db.QueryRow(stmtSQL).Scan(&_database, &createSQL) + err = db.QueryRow(stmtSQL).Scan(&_database, &createSQL) if err != nil { if mysqlErr, ok := err.(*mysql.MySQLError); ok { if mysqlErr.Number == unknownDatabaseErrCode { @@ -116,6 +127,7 @@ func ReadDatabase(d *schema.ResourceData, meta interface{}) error { } } + d.Set("name", name) d.Set("default_character_set", defaultCharset) d.Set("default_collation", defaultCollation) @@ -123,13 +135,16 @@ func ReadDatabase(d *schema.ResourceData, meta interface{}) error { } func DeleteDatabase(d *schema.ResourceData, meta interface{}) error { - db := meta.(*providerConfiguration).DB + db, err := connectToMySQL(meta.(*MySQLConfiguration).Config) + if err != nil { + return err + } name := d.Id() stmtSQL := "DROP DATABASE " + quoteIdentifier(name) log.Println("Executing statement:", stmtSQL) - _, err := db.Exec(stmtSQL) + _, err = db.Exec(stmtSQL) if err == nil { d.SetId("") } diff --git a/mysql/resource_database_test.go b/mysql/resource_database_test.go index c8e6a6025..028a4edd9 100644 --- a/mysql/resource_database_test.go +++ b/mysql/resource_database_test.go @@ -37,29 +37,36 @@ func TestAccDatabase_collationChange(t *testing.T) { collation1 := "latin1_bin" collation2 := "utf8_general_ci" + resourceName := "mysql_database.test" + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccDatabaseCheckDestroy(dbName), Steps: []resource.TestStep{ - resource.TestStep{ + { Config: testAccDatabaseConfig_full(dbName, charset1, collation1), Check: resource.ComposeTestCheckFunc( - testAccDatabaseCheck_full( - "mysql_database.test", dbName, charset1, collation1, - ), + testAccDatabaseCheck_full("mysql_database.test", dbName, charset1, collation1), ), }, - resource.TestStep{ + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { PreConfig: func() { - db := testAccProvider.Meta().(*providerConfiguration).DB - db.Query(fmt.Sprintf("ALTER DATABASE %s CHARACTER SET %s COLLATE %s", dbName, charset2, collation2)) + db, err := connectToMySQL(testAccProvider.Meta().(*MySQLConfiguration).Config) + if err != nil { + return + } + + db.Exec(fmt.Sprintf("ALTER DATABASE %s CHARACTER SET %s COLLATE %s", dbName, charset2, collation2)) }, Config: testAccDatabaseConfig_full(dbName, charset1, collation1), Check: resource.ComposeTestCheckFunc( - testAccDatabaseCheck_full( - "mysql_database.test", dbName, charset1, collation1, - ), + testAccDatabaseCheck_full(resourceName, dbName, charset1, collation1), ), }, }, @@ -81,18 +88,15 @@ func testAccDatabaseCheck_full(rn string, name string, charset string, collation return fmt.Errorf("database id not set") } - db := testAccProvider.Meta().(*providerConfiguration).DB - rows, err := db.Query(fmt.Sprintf("SHOW CREATE DATABASE %s", name)) + db, err := connectToMySQL(testAccProvider.Meta().(*MySQLConfiguration).Config) if err != nil { - return fmt.Errorf("error reading database: %s", err) + return err } - defer rows.Close() - rows.Next() var _name, createSQL string - err = rows.Scan(&_name, &createSQL) + err = db.QueryRow(fmt.Sprintf("SHOW CREATE DATABASE %s", name)).Scan(&_name, &createSQL) if err != nil { - return fmt.Errorf("error scanning create statement: %s", err) + return fmt.Errorf("error reading database: %s", err) } if strings.Index(createSQL, fmt.Sprintf("CHARACTER SET %s", charset)) == -1 { @@ -102,20 +106,19 @@ func testAccDatabaseCheck_full(rn string, name string, charset string, collation return fmt.Errorf("database default collation isn't %s", collation) } - if rows.Next() { - return fmt.Errorf("expected 1 row reading database, but got more") - } - return nil } } func testAccDatabaseCheckDestroy(name string) resource.TestCheckFunc { return func(s *terraform.State) error { - db := testAccProvider.Meta().(*providerConfiguration).DB + db, err := connectToMySQL(testAccProvider.Meta().(*MySQLConfiguration).Config) + if err != nil { + return err + } var _name, createSQL string - err := db.QueryRow(fmt.Sprintf("SHOW CREATE DATABASE %s", name)).Scan(&_name, &createSQL) + err = db.QueryRow(fmt.Sprintf("SHOW CREATE DATABASE %s", name)).Scan(&_name, &createSQL) if err == nil { return fmt.Errorf("database still exists after destroy") } diff --git a/mysql/resource_grant.go b/mysql/resource_grant.go index 27eb6b3c3..c00abcd8e 100644 --- a/mysql/resource_grant.go +++ b/mysql/resource_grant.go @@ -70,7 +70,10 @@ func resourceGrant() *schema.Resource { } func CreateGrant(d *schema.ResourceData, meta interface{}) error { - db := meta.(*providerConfiguration).DB + db, err := connectToMySQL(meta.(*MySQLConfiguration).Config) + if err != nil { + return err + } // create a comma-delimited string of privileges var privileges string @@ -95,7 +98,7 @@ func CreateGrant(d *schema.ResourceData, meta interface{}) error { } log.Println("Executing statement:", stmtSQL) - _, err := db.Exec(stmtSQL) + _, err = db.Exec(stmtSQL) if err != nil { return err } @@ -107,7 +110,10 @@ func CreateGrant(d *schema.ResourceData, meta interface{}) error { } func ReadGrant(d *schema.ResourceData, meta interface{}) error { - db := meta.(*providerConfiguration).DB + db, err := connectToMySQL(meta.(*MySQLConfiguration).Config) + if err != nil { + return err + } stmtSQL := fmt.Sprintf("SHOW GRANTS FOR '%s'@'%s'", d.Get("user").(string), @@ -115,17 +121,19 @@ func ReadGrant(d *schema.ResourceData, meta interface{}) error { log.Println("Executing statement:", stmtSQL) - rows, err := db.Query(stmtSQL) + _, err = db.Exec(stmtSQL) if err != nil { d.SetId("") - } else { - rows.Close() } + return nil } func DeleteGrant(d *schema.ResourceData, meta interface{}) error { - db := meta.(*providerConfiguration).DB + db, err := connectToMySQL(meta.(*MySQLConfiguration).Config) + if err != nil { + return err + } stmtSQL := fmt.Sprintf("REVOKE GRANT OPTION ON %s.%s FROM '%s'@'%s'", d.Get("database").(string), @@ -134,7 +142,7 @@ func DeleteGrant(d *schema.ResourceData, meta interface{}) error { d.Get("host").(string)) log.Println("Executing statement:", stmtSQL) - _, err := db.Query(stmtSQL) + _, err = db.Exec(stmtSQL) if err != nil { return err } diff --git a/mysql/resource_grant_test.go b/mysql/resource_grant_test.go index 041cfbd3a..776f609fd 100644 --- a/mysql/resource_grant_test.go +++ b/mysql/resource_grant_test.go @@ -58,7 +58,11 @@ func testAccPrivilegeExists(rn string, privilege string) resource.TestCheckFunc user := userhost[0] host := userhost[1] - db := testAccProvider.Meta().(*providerConfiguration).DB + db, err := connectToMySQL(testAccProvider.Meta().(*MySQLConfiguration).Config) + if err != nil { + return err + } + stmtSQL := fmt.Sprintf("SHOW GRANTS for '%s'@'%s'", user, host) log.Println("Executing statement:", stmtSQL) rows, err := db.Query(stmtSQL) @@ -90,7 +94,10 @@ func testAccPrivilegeExists(rn string, privilege string) resource.TestCheckFunc } func testAccGrantCheckDestroy(s *terraform.State) error { - db := testAccProvider.Meta().(*providerConfiguration).DB + db, err := connectToMySQL(testAccProvider.Meta().(*MySQLConfiguration).Config) + if err != nil { + return err + } for _, rs := range s.RootModule().Resources { if rs.Type != "mysql_grant" { diff --git a/mysql/resource_user.go b/mysql/resource_user.go index f6f02eb9f..cdc4b0088 100644 --- a/mysql/resource_user.go +++ b/mysql/resource_user.go @@ -64,8 +64,10 @@ func resourceUser() *schema.Resource { } func CreateUser(d *schema.ResourceData, meta interface{}) error { - conf := meta.(*providerConfiguration) - db := meta.(*providerConfiguration).DB + db, err := connectToMySQL(meta.(*MySQLConfiguration).Config) + if err != nil { + return err + } var authStm string var auth string @@ -103,13 +105,18 @@ func CreateUser(d *schema.ResourceData, meta interface{}) error { stmtSQL = stmtSQL + fmt.Sprintf(" IDENTIFIED BY '%s'", password) } - ver, _ := version.NewVersion("5.7.0") - if conf.ServerVersion.GreaterThan(ver) { + requiredVersion, _ := version.NewVersion("5.7.0") + currentVersion, err := serverVersion(db) + if err != nil { + return err + } + + if currentVersion.GreaterThan(requiredVersion) { 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 } @@ -121,7 +128,10 @@ func CreateUser(d *schema.ResourceData, meta interface{}) error { } func UpdateUser(d *schema.ResourceData, meta interface{}) error { - conf := meta.(*providerConfiguration) + db, err := connectToMySQL(meta.(*MySQLConfiguration).Config) + if err != nil { + return err + } var auth string if v, ok := d.GetOk("auth_plugin"); ok { @@ -146,8 +156,13 @@ func UpdateUser(d *schema.ResourceData, meta interface{}) error { var stmtSQL string /* 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 conf.ServerVersion.LessThan(ver) { + if serverVersion.LessThan(ver) { stmtSQL = fmt.Sprintf("SET PASSWORD FOR '%s'@'%s' = PASSWORD('%s')", d.Get("user").(string), d.Get("host").(string), @@ -160,14 +175,19 @@ func UpdateUser(d *schema.ResourceData, meta interface{}) error { } log.Println("Executing query:", stmtSQL) - _, err := conf.DB.Exec(stmtSQL) + _, err = db.Exec(stmtSQL) if err != nil { return err } } - ver, _ := version.NewVersion("5.7.0") - if d.HasChange("tls_option") && conf.ServerVersion.GreaterThan(ver) { + requiredVersion, _ := version.NewVersion("5.7.0") + currentVersion, err := serverVersion(db) + if err != nil { + return err + } + + if d.HasChange("tls_option") && currentVersion.GreaterThan(requiredVersion) { var stmtSQL string stmtSQL = fmt.Sprintf("ALTER USER '%s'@'%s' REQUIRE %s", @@ -176,7 +196,7 @@ func UpdateUser(d *schema.ResourceData, meta interface{}) error { fmt.Sprintf(" REQUIRE %s", d.Get("tls_option").(string))) log.Println("Executing query:", stmtSQL) - _, err := conf.DB.Exec(stmtSQL) + _, err := db.Exec(stmtSQL) if err != nil { return err } @@ -186,7 +206,10 @@ func UpdateUser(d *schema.ResourceData, meta interface{}) error { } func ReadUser(d *schema.ResourceData, meta interface{}) error { - db := meta.(*providerConfiguration).DB + db, err := connectToMySQL(meta.(*MySQLConfiguration).Config) + if err != nil { + return err + } stmtSQL := fmt.Sprintf("SELECT USER FROM mysql.user WHERE USER='%s'", d.Get("user").(string)) @@ -206,7 +229,10 @@ func ReadUser(d *schema.ResourceData, meta interface{}) error { } func DeleteUser(d *schema.ResourceData, meta interface{}) error { - db := meta.(*providerConfiguration).DB + db, err := connectToMySQL(meta.(*MySQLConfiguration).Config) + if err != nil { + return err + } stmtSQL := fmt.Sprintf("DROP USER '%s'@'%s'", d.Get("user").(string), @@ -214,7 +240,7 @@ func DeleteUser(d *schema.ResourceData, meta interface{}) error { log.Println("Executing statement:", stmtSQL) - _, err := db.Exec(stmtSQL) + _, err = db.Exec(stmtSQL) if err == nil { d.SetId("") } diff --git a/mysql/resource_user_test.go b/mysql/resource_user_test.go index 474f855b6..6cc24f379 100644 --- a/mysql/resource_user_test.go +++ b/mysql/resource_user_test.go @@ -108,11 +108,15 @@ func testAccUserExists(rn string) resource.TestCheckFunc { return fmt.Errorf("user id not set") } - db := testAccProvider.Meta().(*providerConfiguration).DB + db, err := connectToMySQL(testAccProvider.Meta().(*MySQLConfiguration).Config) + if err != nil { + return err + } + stmtSQL := fmt.Sprintf("SELECT count(*) from mysql.user where CONCAT(user, '@', host) = '%s'", rs.Primary.ID) log.Println("Executing statement:", stmtSQL) var count int - err := db.QueryRow(stmtSQL).Scan(&count) + err = db.QueryRow(stmtSQL).Scan(&count) if err != nil { if err == sql.ErrNoRows { return fmt.Errorf("expected 1 row reading user but got no rows") @@ -135,11 +139,15 @@ func testAccUserAuthExists(rn string) resource.TestCheckFunc { return fmt.Errorf("user id not set") } - db := testAccProvider.Meta().(*providerConfiguration).DB + db, err := connectToMySQL(testAccProvider.Meta().(*MySQLConfiguration).Config) + if err != nil { + return err + } + stmtSQL := fmt.Sprintf("SELECT count(*) from mysql.user where CONCAT(user, '@', host) = '%s' and plugin = 'mysql_no_login'", rs.Primary.ID) log.Println("Executing statement:", stmtSQL) var count int - err := db.QueryRow(stmtSQL).Scan(&count) + err = db.QueryRow(stmtSQL).Scan(&count) if err != nil { if err == sql.ErrNoRows { return fmt.Errorf("expected 1 row reading user but got no rows") @@ -152,7 +160,10 @@ func testAccUserAuthExists(rn string) resource.TestCheckFunc { } func testAccUserCheckDestroy(s *terraform.State) error { - db := testAccProvider.Meta().(*providerConfiguration).DB + db, err := connectToMySQL(testAccProvider.Meta().(*MySQLConfiguration).Config) + if err != nil { + return err + } for _, rs := range s.RootModule().Resources { if rs.Type != "mysql_user" { diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index eae80872c..055dd145d 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -71,3 +71,4 @@ The following arguments are supported: * `endpoint` - (Required) The address of the MySQL server to use. Most often a "hostname:port" pair, but may also be an absolute path to a Unix socket when the host OS is Unix-compatible. * `username` - (Required) Username to use to authenticate with the server. * `password` - (Optional) Password for the given user, if that user has a password. +* `tls` - (Optional) The TLS configuration. One of `false`, `true`, or `skip-verify`. Defaults to `false`. diff --git a/website/docs/r/database.html.markdown b/website/docs/r/database.html.markdown index c818aa7fd..bbb6632ce 100644 --- a/website/docs/r/database.html.markdown +++ b/website/docs/r/database.html.markdown @@ -57,3 +57,11 @@ The following attributes are exported: * `id` - The id of the database. * `default_character_set` - The default_character_set of the database. * `default_collation` - The default_collation of the database. + +## Import + +Databases can be imported using their name, e.g. + +``` +$ terraform import mysql_database.example my-example-database +``` diff --git a/website/docs/r/grant.html.markdown b/website/docs/r/grant.html.markdown index 299cf3ab4..88f980415 100644 --- a/website/docs/r/grant.html.markdown +++ b/website/docs/r/grant.html.markdown @@ -33,24 +33,12 @@ resource "mysql_grant" "jdoe" { The following arguments are supported: * `user` - (Required) The name of the user. - * `host` - (Optional) The source host of the user. Defaults to "localhost". - -* `database` - (Required) The database to grant privileges on. At this time, - privileges are given to all tables on the database (`mydb.*`). - -* `privileges` - (Required) A list of privileges to grant to the user. Refer - to a list of privileges (such as - [here](https://dev.mysql.com/doc/refman/5.5/en/grant.html)) for applicable - privileges. - -* `tls_option` - (Optional) An TLS-Option for the GRANT-Statement - The Value is suffixed to REQUIRE. F.e. the value 'SSL' will - gernate an SQL like this: `GRANT ..... REQUIRE SSL` - See https://dev.mysql.com/doc/refman/5.7/en/grant.html - -* `grant` - (Optional) Whether to also give the user privileges to grant - the same privileges to other users. +* `database` - (Required) The database to grant privileges on. +* `table` - (Optional) Which table to grant `privileges` on. Defaults to `*`, which is all tables. +* `privileges` - (Required) A list of privileges to grant to the user. Refer to a list of privileges (such as [here](https://dev.mysql.com/doc/refman/5.5/en/grant.html)) for applicable privileges. +* `tls_option` - (Optional) An TLS-Option for the `GRANT` statement. The value is suffixed to `REQUIRE`. A value of 'SSL' will generate a `GRANT ... REQUIRE SSL` statement. See the [MYSQL `GRANT` documentation](https://dev.mysql.com/doc/refman/5.7/en/grant.html) for more. Ignored if MySQL version is under 5.7.0. +* `grant` - (Optional) Whether to also give the user privileges to grant the same privileges to other users. ## Attributes Reference diff --git a/website/docs/r/user.html.markdown b/website/docs/r/user.html.markdown index 1318bc3f7..fd17b1210 100644 --- a/website/docs/r/user.html.markdown +++ b/website/docs/r/user.html.markdown @@ -41,29 +41,11 @@ resource "mysql_user" "nologin" { The following arguments are supported: * `user` - (Required) The name of the user. - * `host` - (Optional) The source host of the user. Defaults to "localhost". - -* `plaintext_password` - (Optional) The password for the user. This must be - provided in plain text, so the data source for it must be secured. - An _unsalted_ hash of the provided password is stored in state. Conflicts - with `auth_plugin`. - -* `password` - (Optional) Deprecated alias of `plaintext_password`, whose - value is *stored as plaintext in state*. Prefer to use `plaintext_password` - instead, which stores the password as an unsalted hash. Conflicts with - `auth_plugin`. - -* `auth_plugin` - (Optional) Use an [authentication plugin][ref-auth-plugins] - to authenticate the user instead of using password authentication. - Description of the fields allowed in the block below. Conflicts with - `password` and `plaintext_password`. - -* `tls_option` - (Optional) An TLS-Option for the CREATE USER-Statement or ALTER USER - The Value is suffixed to REQUIRE. F.e. the value 'SSL' will - gernate an SQL like this: `CREATE USER ..... REQUIRE SSL` - See https://dev.mysql.com/doc/refman/5.7/en/create-user.html - For MySql-Server-Versions less than 5.7 this options will be ignored. +* `plaintext_password` - (Optional) The password for the user. This must be provided in plain text, so the data source for it must be secured. An _unsalted_ hash of the provided password is stored in state. Conflicts with `auth_plugin`. +* `password` - (Optional) Deprecated alias of `plaintext_password`, whose value is *stored as plaintext in state*. Prefer to use `plaintext_password` instead, which stores the password as an unsalted hash. Conflicts with `auth_plugin`. +* `auth_plugin` - (Optional) Use an [authentication plugin][ref-auth-plugins] to authenticate the user instead of using password authentication. Description of the fields allowed in the block below. Conflicts with `password` and `plaintext_password`. +* `tls_option` - (Optional) An TLS-Option for the `CREATE USER` or `ALTER USER` statement. The value is suffixed to `REQUIRE`. A value of 'SSL' will generate a `CREATE USER ... REQUIRE SSL` statement. See the [MYSQL `CREATE USER` documentation](https://dev.mysql.com/doc/refman/5.7/en/create-user.html) for more. Ignored if MySQL version is under 5.7.0. [ref-auth-plugins]: https://dev.mysql.com/doc/refman/5.7/en/authentication-plugins.html @@ -90,3 +72,7 @@ The following attributes are exported: * `password` - The password of the user. * `id` - The id of the user created, composed as "username@host". * `host` - The host where the user was created. + +## Attributes Reference + +No further attributes are exported.