Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for abandoning sql user #2719

Merged
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
3 changes: 3 additions & 0 deletions .changelog/4231.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
sql: added `deletion_policy` field to `google_sql_user` to enable abandoning users rather than deleting them
```
17 changes: 17 additions & 0 deletions google-beta/resource_sql_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
sqladmin "google.golang.org/api/sqladmin/v1beta4"
)

Expand Down Expand Up @@ -65,6 +66,15 @@ func resourceSqlUser() *schema.Resource {
ForceNew: true,
Description: `The ID of the project in which the resource belongs. If it is not provided, the provider project is used.`,
},

"deletion_policy": {
Type: schema.TypeString,
Optional: true,
Description: `The deletion policy for the user. Setting ABANDON allows the resource
to be abandoned rather than deleted. This is useful for Postgres, where users cannot be deleted from the API if they
have been granted SQL roles. Possible values are: "ABANDON".`,
ValidateFunc: validation.StringInSlice([]string{"ABANDON", ""}, false),
},
},
}
}
Expand Down Expand Up @@ -236,6 +246,13 @@ func resourceSqlUserUpdate(d *schema.ResourceData, meta interface{}) error {

func resourceSqlUserDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)

if deletionPolicy := d.Get("deletion_policy"); deletionPolicy == "ABANDON" {
// Allows for user to be abandoned without deletion to avoid deletion failing
// for Postgres users in some circumstances due to existing SQL roles
return nil
}

userAgent, err := generateUserAgentString(d, config.userAgent)
if err != nil {
return err
Expand Down
92 changes: 92 additions & 0 deletions google-beta/resource_sql_user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,40 @@ func TestAccSqlUser_postgres(t *testing.T) {
})
}

func TestAccSqlUser_postgresAbandon(t *testing.T) {
t.Parallel()

instance := fmt.Sprintf("i-%d", randInt(t))
userName := "admin"
vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlUserDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testGoogleSqlUser_postgresAbandon(instance, userName),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleSqlUserExists(t, "google_sql_user.user"),
),
},
{
ResourceName: "google_sql_user.user",
ImportStateId: fmt.Sprintf("%s/%s/admin", getTestProjectFromEnv(), instance),
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"password", "deletion_policy"},
},
{
// Abandon user
Config: testGoogleSqlUser_postgresNoUser(instance),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleSqlUserExistsWithName(t, instance, userName),
),
},
},
})
}

func testAccCheckGoogleSqlUserExists(t *testing.T, n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
config := googleProviderConfig(t)
Expand Down Expand Up @@ -106,6 +140,27 @@ func testAccCheckGoogleSqlUserExists(t *testing.T, n string) resource.TestCheckF
}
}

func testAccCheckGoogleSqlUserExistsWithName(t *testing.T, instance, name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
config := googleProviderConfig(t)

users, err := config.NewSqlAdminClient(config.userAgent).Users.List(config.Project,
instance).Do()

if err != nil {
return err
}

for _, user := range users.Items {
if user.Name == name {
return nil
}
}

return fmt.Errorf("Not found: User: %s in instance: %s: %s", name, instance, err)
}
}

func testAccSqlUserDestroyProducer(t *testing.T) func(s *terraform.State) error {
return func(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
Expand Down Expand Up @@ -180,3 +235,40 @@ resource "google_sql_user" "user" {
}
`, instance, password)
}

func testGoogleSqlUser_postgresAbandon(instance, name 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"
}
}

resource "google_sql_user" "user" {
name = "%s"
instance = google_sql_database_instance.instance.name
password = "password"
deletion_policy = "ABANDON"
}
`, instance, name)
}

func testGoogleSqlUser_postgresNoUser(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"
}
}
`, instance)
}
6 changes: 6 additions & 0 deletions website/docs/r/sql_user.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ The following arguments are supported:
* `password` - (Optional) The password for the user. Can be updated. For Postgres
instances this is a Required field.

* `deletion_policy` - (Optional) The deletion policy for the user.
Setting `ABANDON` allows the resource to be abandoned rather than deleted. This is useful
for Postgres, where users cannot be deleted from the API if they have been granted SQL roles.

Possible values are: `ABANDON`.

- - -

* `host` - (Optional) The host the user can connect from. This is only supported
Expand Down