Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions mmv1/third_party/terraform/services/sql/resource_sql_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,23 @@ func diffSuppressIamUserName(_, old, new string, d *schema.ResourceData) bool {
return true
}

// MySQL casts all hostnames to lowercase. For MySQL Cloud IAM Groups
// make sure comparison checks lowercase everything after the "@" symbol.
// Only MySQL has "%" populated for empty hostnames so we can use
// that to identify MySQL Cloud IAM Groups.
if strings.Contains(userType, "CLOUD_IAM_GROUP") && d.Get("host") == "%" {
splitName := strings.Split(new, "@")
if len(splitName) >= 2 {
groupUsername := splitName[0]
groupHostname := splitName[1]
groupName := groupUsername + "@" + strings.ToLower(groupHostname)
if old == groupName {
return true
}
}
}


return false
}

Expand Down Expand Up @@ -392,6 +409,10 @@ func resourceSqlUserRead(d *schema.ResourceData, meta interface{}) error {
var username string
if !(strings.Contains(databaseInstance.DatabaseVersion, "POSTGRES") || currentUser.Type == "CLOUD_IAM_GROUP") {
username = strings.Split(name, "@")[0]
} else if strings.Contains(databaseInstance.DatabaseVersion, "MYSQL") && currentUser.Type == "CLOUD_IAM_GROUP" {
groupUsername := strings.Split(name, "@")[0]
groupHostname := strings.ToLower(strings.Split(name, "@")[1])
username = groupUsername + "@" + groupHostname
} else {
username = name
}
Expand Down
113 changes: 108 additions & 5 deletions mmv1/third_party/terraform/services/sql/resource_sql_user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,66 @@ func TestAccSqlUser_iamGroupUser(t *testing.T) {
CheckDestroy: testAccSqlUserDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testGoogleSqlUser_iamGroupUser(instance),
Config: testGoogleSqlUser_iamGroupUser("iam-group-auth-test-group@google.com", instance),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleSqlUserExists(t, "google_sql_user.user"),
),
},
{
ResourceName: "google_sql_user.user",
ImportStateId: fmt.Sprintf("%s/%s/iam-group-auth-test-group@google.com", envvar.GetTestProjectFromEnv(), instance),
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"password"},
},
},
})
}

func TestAccSqlUser_iamGroupUser_capitalizedHostName(t *testing.T) {
// Multiple fine-grained resources
acctest.SkipIfVcr(t)
t.Parallel()

instance := fmt.Sprintf("tf-test-%d", acctest.RandInt(t))
acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccSqlUserDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testGoogleSqlUser_iamGroupUser("iam-group-auth-test-group@GOOGLE.com", instance),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleSqlUserExists(t, "google_sql_user.user"),
),
},
{
ResourceName: "google_sql_user.user",
ImportStateId: fmt.Sprintf("%s/%s/iam-group-auth-test-group@google.com", envvar.GetTestProjectFromEnv(), instance),
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"password"},
},
},
})
}

func TestAccSqlUser_postgres_iamGroupUser(t *testing.T) {
// Multiple fine-grained resources
acctest.SkipIfVcr(t)
t.Parallel()

instance := fmt.Sprintf("tf-test-%d", acctest.RandInt(t))
acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
ExternalProviders: map[string]resource.ExternalProvider{
"time": {},
},
CheckDestroy: testAccSqlUserDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testGoogleSqlUser_postgres_iamGroupUser("iam-group-auth-test-group@google.com", instance),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleSqlUserExists(t, "google_sql_user.user"),
),
Expand Down Expand Up @@ -259,6 +318,10 @@ func testAccCheckGoogleSqlUserExists(t *testing.T, n string) resource.TestCheckF
name := rs.Primary.Attributes["name"]
instance := rs.Primary.Attributes["instance"]
host := rs.Primary.Attributes["host"]
databaseInstance, err := sql.NewClient(config, config.UserAgent).Instances.Get(config.Project, instance).Do()
if err != nil {
return err
}
users, err := sql.NewClient(config, config.UserAgent).Users.List(config.Project,
instance).Do()

Expand All @@ -267,7 +330,15 @@ func testAccCheckGoogleSqlUserExists(t *testing.T, n string) resource.TestCheckF
}

for _, user := range users.Items {
if user.Name == name && user.Host == host {
username := name
if user.Type == "CLOUD_IAM_GROUP" && strings.Contains(databaseInstance.DatabaseVersion, "MYSQL") {
if len(strings.Split(name, "@")) >= 2 {
groupUsername := strings.Split(name, "@")[0]
groupHostname := strings.ToLower(strings.Split(name, "@")[1])
username = groupUsername + "@" + groupHostname
}
}
if user.Name == username && user.Host == host {
return nil
}
}
Expand Down Expand Up @@ -1091,7 +1162,7 @@ resource "google_project_iam_member" "sa_user" {
`, instance, instance, instance, instance)
}

func testGoogleSqlUser_iamGroupUser(instance string) string {
func testGoogleSqlUser_iamGroupUser(username, instance string) string {
return fmt.Sprintf(`
resource "google_sql_database_instance" "instance" {
name = "%s"
Expand All @@ -1108,9 +1179,41 @@ resource "google_sql_database_instance" "instance" {
}

resource "google_sql_user" "user" {
name = "iam-group-auth-test-group@google.com"
name = "%s"
instance = google_sql_database_instance.instance.name
type = "CLOUD_IAM_GROUP"
}
`, instance)
`, instance, username)
}

func testGoogleSqlUser_postgres_iamGroupUser(username, instance string) string {
return fmt.Sprintf(`
resource "google_sql_database_instance" "instance" {
name = "%s"
region = "us-central1"
database_version = "POSTGRES_9_6"
deletion_protection = false
settings {
tier = "db-f1-micro"
database_flags {
name = "cloudsql.iam_authentication"
value = "on"
}
}
}

# TODO: Remove with resolution of https://github.com/hashicorp/terraform-provider-google/issues/14233
resource "time_sleep" "wait_60_seconds" {
depends_on = [google_sql_database_instance.instance]

create_duration = "60s"
}

resource "google_sql_user" "user" {
depends_on = [time_sleep.wait_60_seconds]
name = "%s"
instance = google_sql_database_instance.instance.name
type = "CLOUD_IAM_GROUP"
}
`, instance, username)
}
Loading