From d66eb4ead70536b034d057aea82074129b08c905 Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Thu, 17 Oct 2024 19:35:38 +0000 Subject: [PATCH] Update `google_sql_database` and `google_sql_user` to not do Read actions when instance is not active (#11866) Co-authored-by: Sarah French <15078782+SarahFrench@users.noreply.github.com> [upstream:fa2e68e34f9b8cc68d8245cc307741fd601beb3d] Signed-off-by: Modular Magician --- .changelog/11866.txt | 3 + .../services/sql/resource_sql_database.go | 8 +++ .../sql/resource_sql_database_test.go | 61 +++++++++++++++++++ google-beta/services/sql/resource_sql_user.go | 12 ++-- .../services/sql/resource_sql_user_test.go | 59 ++++++++++++++++++ 5 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 .changelog/11866.txt diff --git a/.changelog/11866.txt b/.changelog/11866.txt new file mode 100644 index 0000000000..53eb650a41 --- /dev/null +++ b/.changelog/11866.txt @@ -0,0 +1,3 @@ +```release-note:none +sql: updated `google_sql_database` and `google_sql_user` so they don't perform Read operations if their associated `google_sql_database_instance` has `activation_policy` set to "NEVER". This avoids triggering API errors while the instance is unavailable. +``` \ No newline at end of file diff --git a/google-beta/services/sql/resource_sql_database.go b/google-beta/services/sql/resource_sql_database.go index 1e1a63f5e4..d8dba5a030 100644 --- a/google-beta/services/sql/resource_sql_database.go +++ b/google-beta/services/sql/resource_sql_database.go @@ -234,6 +234,14 @@ func resourceSQLDatabaseRead(d *schema.ResourceData, meta interface{}) error { } headers := make(http.Header) + instance := d.Get("instance").(string) + databaseInstance, err := config.NewSqlAdminClient(userAgent).Instances.Get(project, instance).Do() + if err != nil { + return err + } + if databaseInstance.Settings.ActivationPolicy != "ALWAYS" { + return nil + } res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ Config: config, Method: "GET", diff --git a/google-beta/services/sql/resource_sql_database_test.go b/google-beta/services/sql/resource_sql_database_test.go index 38ad57b040..04298d009c 100644 --- a/google-beta/services/sql/resource_sql_database_test.go +++ b/google-beta/services/sql/resource_sql_database_test.go @@ -185,6 +185,67 @@ func testAccSqlDatabaseDestroyProducer(t *testing.T) func(s *terraform.State) er } } +func TestAccSqlDatabase_instanceWithActivationPolicy(t *testing.T) { + t.Parallel() + + var database sqladmin.Database + + instance_name := fmt.Sprintf("tf-test-%d", acctest.RandInt(t)) + database_name := fmt.Sprintf("tf-test-%d", acctest.RandInt(t)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccSqlDatabaseDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testGoogleSqlDatabase_instanceWithActivationPolicy(instance_name, database_name, "ALWAYS"), + Check: resource.ComposeTestCheckFunc( + testAccCheckGoogleSqlDatabaseExists( + t, "google_sql_database.database", &database), + ), + }, + // Step 2: Update activation_policy to NEVER + { + Config: testGoogleSqlDatabase_instanceWithActivationPolicy(instance_name, database_name, "NEVER"), + }, + // Step 3: Refresh to verify no errors + { + Config: testGoogleSqlDatabase_instanceWithActivationPolicy(instance_name, database_name, "NEVER"), + }, + // Step 4: Update activation_policy to ALWAYS so that post-test destroy code is able to delete the google_sql_database resource + { + Config: testGoogleSqlDatabase_instanceWithActivationPolicy(instance_name, database_name, "ALWAYS"), + Check: resource.ComposeTestCheckFunc( + testAccCheckGoogleSqlDatabaseExists( + t, "google_sql_database.database", &database), + ), + }, + }, + }) +} + +func testGoogleSqlDatabase_instanceWithActivationPolicy(instance_name, database_name, activationPolicy string) string { + return fmt.Sprintf(` +resource "google_sql_database_instance" "instance" { + name = "%s" + database_version = "MYSQL_5_7" + region = "us-central1" + deletion_protection = false + settings { + tier = "db-f1-micro" + availability_type = "ZONAL" + activation_policy = "%s" + } +} + +resource "google_sql_database" "database" { + name = "%s" + instance = google_sql_database_instance.instance.name + } +`, instance_name, activationPolicy, database_name) +} + var testGoogleSqlDatabase_basic = ` resource "google_sql_database_instance" "instance" { name = "%s" diff --git a/google-beta/services/sql/resource_sql_user.go b/google-beta/services/sql/resource_sql_user.go index 85c5c8649a..8f5dfe4c20 100644 --- a/google-beta/services/sql/resource_sql_user.go +++ b/google-beta/services/sql/resource_sql_user.go @@ -328,6 +328,13 @@ func resourceSqlUserRead(d *schema.ResourceData, meta interface{}) error { instance := d.Get("instance").(string) name := d.Get("name").(string) host := d.Get("host").(string) + databaseInstance, err := config.NewSqlAdminClient(userAgent).Instances.Get(project, instance).Do() + if err != nil { + return err + } + if databaseInstance.Settings.ActivationPolicy != "ALWAYS" { + return nil + } var users *sqladmin.UsersListResponse err = nil @@ -344,11 +351,6 @@ func resourceSqlUserRead(d *schema.ResourceData, meta interface{}) error { } var user *sqladmin.User - databaseInstance, err := config.NewSqlAdminClient(userAgent).Instances.Get(project, instance).Do() - if err != nil { - return err - } - for _, currentUser := range users.Items { var username string if !(strings.Contains(databaseInstance.DatabaseVersion, "POSTGRES") || currentUser.Type == "CLOUD_IAM_GROUP") { diff --git a/google-beta/services/sql/resource_sql_user_test.go b/google-beta/services/sql/resource_sql_user_test.go index df68378705..8d429740f3 100644 --- a/google-beta/services/sql/resource_sql_user_test.go +++ b/google-beta/services/sql/resource_sql_user_test.go @@ -326,6 +326,65 @@ func TestAccSqlUser_mysqlPasswordPolicy(t *testing.T) { }) } +func TestAccSqlUser_instanceWithActivationPolicy(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_instanceWithActivationPolicy(instance, "ALWAYS"), + Check: resource.ComposeTestCheckFunc( + testAccCheckGoogleSqlUserExists(t, "google_sql_user.user"), + ), + }, + // Step 2: Update activation_policy to NEVER + { + Config: testGoogleSqlUser_instanceWithActivationPolicy(instance, "NEVER"), + }, + // Step 3: Refresh to verify no errors + { + Config: testGoogleSqlUser_instanceWithActivationPolicy(instance, "NEVER"), + }, + // Step 4: Update activation_policy to ALWAYS so that post-test destroy code is able to delete the google_sql_user resource + { + Config: testGoogleSqlUser_instanceWithActivationPolicy(instance, "ALWAYS"), + Check: resource.ComposeTestCheckFunc( + testAccCheckGoogleSqlUserExists(t, "google_sql_user.user"), + ), + }, + }, + }) +} + +func testGoogleSqlUser_instanceWithActivationPolicy(instance, activationPolicy string) string { + return fmt.Sprintf(` +resource "google_sql_database_instance" "instance" { + name = "%s" + database_version = "MYSQL_5_7" + region = "us-central1" + deletion_protection = false + settings { + tier = "db-f1-micro" + availability_type = "ZONAL" + activation_policy = "%s" + } +} + +resource "google_sql_user" "user" { + name = "admin" + instance = google_sql_database_instance.instance.name + password = "password" + } +`, instance, activationPolicy) +} + func testGoogleSqlUser_mysql(instance, password string) string { return fmt.Sprintf(` resource "google_sql_database_instance" "instance" {