From 12f0beaf09f7487fc6ad0abb3e496d743e348d42 Mon Sep 17 00:00:00 2001 From: Dennis Pattmann Date: Wed, 24 Aug 2022 11:06:37 +0200 Subject: [PATCH 01/13] Makes availability_zone optional/computed to support HA bundle_ids --- internal/service/lightsail/database.go | 3 ++- website/docs/r/lightsail_database.html.markdown | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/service/lightsail/database.go b/internal/service/lightsail/database.go index 9f2ec891b532..4146f584463a 100644 --- a/internal/service/lightsail/database.go +++ b/internal/service/lightsail/database.go @@ -42,7 +42,8 @@ func ResourceDatabase() *schema.Resource { }, "availability_zone": { Type: schema.TypeString, - Required: true, + Optional: true, + Computed: true, ForceNew: true, }, "backup_retention_enabled": { diff --git a/website/docs/r/lightsail_database.html.markdown b/website/docs/r/lightsail_database.html.markdown index dc708787af2c..ac3ca5dde245 100644 --- a/website/docs/r/lightsail_database.html.markdown +++ b/website/docs/r/lightsail_database.html.markdown @@ -104,7 +104,7 @@ resource "aws_lightsail_database" "test" { The following arguments are supported: * `name` - (Required) The name to use for your new Lightsail database resource. Names be unique within each AWS Region in your Lightsail account. -* `availability_zone` - (Required) The Availability Zone in which to create your new database. Use the us-east-2a case-sensitive format. +* `availability_zone` - The Availability Zone in which to create your new database. Use the us-east-2a case-sensitive format. * `master_database_name` - (Required) The name of the master database created when the Lightsail database resource is created. * `master_password` - (Sensitive) The password for the master user of your new database. The password can include any printable ASCII character except "/", """, or "@". * `master_username` - The master user name for your new database. From 682963c86bbdcf4a51dae243318e29e6558a6b7b Mon Sep 17 00:00:00 2001 From: Dennis Pattmann Date: Wed, 24 Aug 2022 11:07:14 +0200 Subject: [PATCH 02/13] Update aws_lightsail_database resource to support ctx and timeouts --- internal/service/lightsail/database.go | 109 ++++++++++-------- internal/service/lightsail/wait.go | 12 +- .../docs/r/lightsail_database.html.markdown | 9 ++ 3 files changed, 73 insertions(+), 57 deletions(-) diff --git a/internal/service/lightsail/database.go b/internal/service/lightsail/database.go index 4146f584463a..8e81331b1a4e 100644 --- a/internal/service/lightsail/database.go +++ b/internal/service/lightsail/database.go @@ -1,7 +1,7 @@ package lightsail import ( - "fmt" + "context" "log" "regexp" "time" @@ -9,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/lightsail" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -22,12 +23,12 @@ const ( func ResourceDatabase() *schema.Resource { return &schema.Resource{ - Create: resourceDatabaseCreate, - Read: resourceDatabaseRead, - Update: resourceDatabaseUpdate, - Delete: resourceDatabaseDelete, + CreateContext: resourceDatabaseCreate, + ReadContext: resourceDatabaseRead, + UpdateContext: resourceDatabaseUpdate, + DeleteContext: resourceDatabaseDelete, Importer: &schema.ResourceImporter{ - State: ResourceDatabaseImport, + StateContext: ResourceDatabaseImport, }, Schema: map[string]*schema.Schema{ @@ -176,11 +177,17 @@ func ResourceDatabase() *schema.Resource { "tags": tftags.TagsSchema(), "tags_all": tftags.TagsSchemaComputed(), }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, CustomizeDiff: verify.SetTagsDiff, } } -func resourceDatabaseCreate(d *schema.ResourceData, meta interface{}) error { +func resourceDatabaseCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).LightsailConn defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{}))) @@ -217,21 +224,21 @@ func resourceDatabaseCreate(d *schema.ResourceData, meta interface{}) error { req.Tags = Tags(tags.IgnoreAWS()) } - resp, err := conn.CreateRelationalDatabase(&req) + resp, err := conn.CreateRelationalDatabaseWithContext(ctx, &req) if err != nil { - return err + return diag.FromErr(err) } if len(resp.Operations) == 0 { - return fmt.Errorf("No operations found for Create Relational Database request") + return diag.Errorf("No operations found for Create Relational Database request") } op := resp.Operations[0] d.SetId(d.Get("relational_database_name").(string)) - err = waitOperation(conn, op.Id) + err = waitOperation(ctx, conn, op.Id) if err != nil { - return fmt.Errorf("Error waiting for Relational Database (%s) to become ready: %s", d.Id(), err) + return diag.Errorf("Error waiting for Relational Database (%s) to become ready: %s", d.Id(), err) } // Backup Retention is not a value you can pass on creation and defaults to true. @@ -244,46 +251,46 @@ func resourceDatabaseCreate(d *schema.ResourceData, meta interface{}) error { DisableBackupRetention: aws.Bool(true), } - resp, err := conn.UpdateRelationalDatabase(&req) + resp, err := conn.UpdateRelationalDatabaseWithContext(ctx, &req) if err != nil { - return err + return diag.FromErr(err) } if len(resp.Operations) == 0 { - return fmt.Errorf("No operations found for Update Relational Database request") + return diag.Errorf("No operations found for Update Relational Database request") } op := resp.Operations[0] - err = waitOperation(conn, op.Id) + err = waitOperation(ctx, conn, op.Id) if err != nil { - return fmt.Errorf("Error waiting for Relational Database (%s) to become ready: %s", d.Id(), err) + return diag.Errorf("Error waiting for Relational Database (%s) to become ready: %s", d.Id(), err) } - err = waitDatabaseBackupRetentionModified(conn, aws.String(d.Id()), aws.Bool(v.(bool))) + err = waitDatabaseBackupRetentionModified(ctx, conn, aws.String(d.Id()), aws.Bool(v.(bool))) if err != nil { - return fmt.Errorf("Error waiting for Relational Database (%s) Backup Retention to be updated: %s", d.Id(), err) + return diag.Errorf("Error waiting for Relational Database (%s) Backup Retention to be updated: %s", d.Id(), err) } } // Some Operations can complete before the Database enters the Available state. Added a waiter to make sure the Database is available before continuing. - _, err = waitDatabaseModified(conn, aws.String(d.Id())) + _, err = waitDatabaseModified(ctx, conn, aws.String(d.Id())) if err != nil { - return fmt.Errorf("Error waiting for Relational Database (%s) to become available: %s", d.Id(), err) + return diag.Errorf("Error waiting for Relational Database (%s) to become available: %s", d.Id(), err) } - return resourceDatabaseRead(d, meta) + return resourceDatabaseRead(ctx, d, meta) } -func resourceDatabaseRead(d *schema.ResourceData, meta interface{}) error { +func resourceDatabaseRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).LightsailConn defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig // Some Operations can complete before the Database enters the Available state. Added a waiter to make sure the Database is available before continuing. // This is to support importing a resource that is not in a ready state. - database, err := waitDatabaseModified(conn, aws.String(d.Id())) + database, err := waitDatabaseModified(ctx, conn, aws.String(d.Id())) if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, lightsail.ErrCodeNotFoundException) { log.Printf("[WARN] Lightsail Relational Database (%s) not found, removing from state", d.Id()) @@ -292,7 +299,7 @@ func resourceDatabaseRead(d *schema.ResourceData, meta interface{}) error { } if err != nil { - return fmt.Errorf("error reading LightSail Relational Database (%s): %w", d.Id(), err) + return diag.Errorf("error reading LightSail Relational Database (%s): %s", d.Id(), err) } rd := database.RelationalDatabase @@ -324,23 +331,23 @@ func resourceDatabaseRead(d *schema.ResourceData, meta interface{}) error { //lintignore:AWSR002 if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { - return fmt.Errorf("error setting tags: %w", err) + return diag.Errorf("error setting tags: %s", err) } if err := d.Set("tags_all", tags.Map()); err != nil { - return fmt.Errorf("error setting tags_all: %w", err) + return diag.Errorf("error setting tags_all: %s", err) } return nil } -func resourceDatabaseDelete(d *schema.ResourceData, meta interface{}) error { +func resourceDatabaseDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).LightsailConn // Some Operations can complete before the Database enters the Available state. Added a waiter to make sure the Database is available before continuing. - _, err := waitDatabaseModified(conn, aws.String(d.Id())) + _, err := waitDatabaseModified(ctx, conn, aws.String(d.Id())) if err != nil { - return fmt.Errorf("Error waiting for Relational Database (%s) to become available: %s", d.Id(), err) + return diag.Errorf("Error waiting for Relational Database (%s) to become available: %s", d.Id(), err) } skipFinalSnapshot := d.Get("skip_final_snapshot").(bool) @@ -354,28 +361,28 @@ func resourceDatabaseDelete(d *schema.ResourceData, meta interface{}) error { if name, present := d.GetOk("final_snapshot_name"); present { req.FinalRelationalDatabaseSnapshotName = aws.String(name.(string)) } else { - return fmt.Errorf("Lightsail Database FinalRelationalDatabaseSnapshotName is required when a final snapshot is required") + return diag.Errorf("Lightsail Database FinalRelationalDatabaseSnapshotName is required when a final snapshot is required") } } - resp, err := conn.DeleteRelationalDatabase(&req) + resp, err := conn.DeleteRelationalDatabaseWithContext(ctx, &req) if err != nil { - return err + return diag.FromErr(err) } op := resp.Operations[0] - err = waitOperation(conn, op.Id) + err = waitOperation(ctx, conn, op.Id) if err != nil { - return fmt.Errorf("Error waiting for Relational Database (%s) to Delete: %s", d.Id(), err) + return diag.Errorf("Error waiting for Relational Database (%s) to Delete: %s", d.Id(), err) } return nil } func ResourceDatabaseImport( - d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { // Neither skip_final_snapshot nor final_snapshot_identifier can be fetched // from any API call, so we need to default skip_final_snapshot to true so // that final_snapshot_identifier is not required @@ -383,7 +390,7 @@ func ResourceDatabaseImport( return []*schema.ResourceData{d}, nil } -func resourceDatabaseUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceDatabaseUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).LightsailConn requestUpdate := false @@ -429,48 +436,48 @@ func resourceDatabaseUpdate(d *schema.ResourceData, meta interface{}) error { if d.HasChange("tags") { o, n := d.GetChange("tags") - if err := UpdateTags(conn, d.Id(), o, n); err != nil { - return fmt.Errorf("error updating Lightsail Database (%s) tags: %s", d.Id(), err) + if err := UpdateTagsWithContext(ctx, conn, d.Id(), o, n); err != nil { + return diag.Errorf("error updating Lightsail Database (%s) tags: %s", d.Id(), err) } } if d.HasChange("tags_all") { o, n := d.GetChange("tags_all") - if err := UpdateTags(conn, d.Id(), o, n); err != nil { - return fmt.Errorf("error updating Lightsail Database (%s) tags: %s", d.Id(), err) + if err := UpdateTagsWithContext(ctx, conn, d.Id(), o, n); err != nil { + return diag.Errorf("error updating Lightsail Database (%s) tags: %s", d.Id(), err) } } if requestUpdate { - resp, err := conn.UpdateRelationalDatabase(&req) + resp, err := conn.UpdateRelationalDatabaseWithContext(ctx, &req) if err != nil { - return err + return diag.FromErr(err) } if len(resp.Operations) == 0 { - return fmt.Errorf("No operations found for Update Relational Database request") + return diag.Errorf("No operations found for Update Relational Database request") } op := resp.Operations[0] - err = waitOperation(conn, op.Id) + err = waitOperation(ctx, conn, op.Id) if err != nil { - return fmt.Errorf("Error waiting for Relational Database (%s) to become ready: %s", d.Id(), err) + return diag.Errorf("Error waiting for Relational Database (%s) to become ready: %s", d.Id(), err) } if d.HasChange("backup_retention_enabled") { - err = waitDatabaseBackupRetentionModified(conn, aws.String(d.Id()), aws.Bool(d.Get("backup_retention_enabled").(bool))) + err = waitDatabaseBackupRetentionModified(ctx, conn, aws.String(d.Id()), aws.Bool(d.Get("backup_retention_enabled").(bool))) if err != nil { - return fmt.Errorf("Error waiting for Relational Database (%s) Backup Retention to be updated: %s", d.Id(), err) + return diag.Errorf("Error waiting for Relational Database (%s) Backup Retention to be updated: %s", d.Id(), err) } } // Some Operations can complete before the Database enters the Available state. Added a waiter to make sure the Database is available before continuing. - _, err = waitDatabaseModified(conn, aws.String(d.Id())) + _, err = waitDatabaseModified(ctx, conn, aws.String(d.Id())) if err != nil { - return fmt.Errorf("Error waiting for Relational Database (%s) to become available: %s", d.Id(), err) + return diag.Errorf("Error waiting for Relational Database (%s) to become available: %s", d.Id(), err) } } - return resourceDatabaseRead(d, meta) + return resourceDatabaseRead(ctx, d, meta) } diff --git a/internal/service/lightsail/wait.go b/internal/service/lightsail/wait.go index 14b545d486dd..c180a97733df 100644 --- a/internal/service/lightsail/wait.go +++ b/internal/service/lightsail/wait.go @@ -35,7 +35,7 @@ const ( ) // waitOperation waits for an Operation to return Succeeded or Compleated -func waitOperation(conn *lightsail.Lightsail, oid *string) error { +func waitOperation(ctx context.Context, conn *lightsail.Lightsail, oid *string) error { stateConf := &resource.StateChangeConf{ Pending: []string{lightsail.OperationStatusStarted}, Target: []string{lightsail.OperationStatusCompleted, lightsail.OperationStatusSucceeded}, @@ -45,7 +45,7 @@ func waitOperation(conn *lightsail.Lightsail, oid *string) error { MinTimeout: OperationMinTimeout, } - outputRaw, err := stateConf.WaitForState() + outputRaw, err := stateConf.WaitForStateContext(ctx) if _, ok := outputRaw.(*lightsail.GetOperationOutput); ok { return err @@ -55,7 +55,7 @@ func waitOperation(conn *lightsail.Lightsail, oid *string) error { } // waitDatabaseModified waits for a Modified Database return available -func waitDatabaseModified(conn *lightsail.Lightsail, db *string) (*lightsail.GetRelationalDatabaseOutput, error) { +func waitDatabaseModified(ctx context.Context, conn *lightsail.Lightsail, db *string) (*lightsail.GetRelationalDatabaseOutput, error) { stateConf := &resource.StateChangeConf{ Pending: []string{DatabaseStateModifying}, Target: []string{DatabaseStateAvailable}, @@ -65,7 +65,7 @@ func waitDatabaseModified(conn *lightsail.Lightsail, db *string) (*lightsail.Get MinTimeout: DatabaseMinTimeout, } - outputRaw, err := stateConf.WaitForState() + outputRaw, err := stateConf.WaitForStateContext(ctx) if output, ok := outputRaw.(*lightsail.GetRelationalDatabaseOutput); ok { return output, err @@ -76,7 +76,7 @@ func waitDatabaseModified(conn *lightsail.Lightsail, db *string) (*lightsail.Get // waitDatabaseBackupRetentionModified waits for a Modified BackupRetention on Database return available -func waitDatabaseBackupRetentionModified(conn *lightsail.Lightsail, db *string, status *bool) error { +func waitDatabaseBackupRetentionModified(ctx context.Context, conn *lightsail.Lightsail, db *string, status *bool) error { stateConf := &resource.StateChangeConf{ Pending: []string{strconv.FormatBool(!aws.BoolValue(status))}, Target: []string{strconv.FormatBool(aws.BoolValue(status))}, @@ -86,7 +86,7 @@ func waitDatabaseBackupRetentionModified(conn *lightsail.Lightsail, db *string, MinTimeout: DatabaseMinTimeout, } - outputRaw, err := stateConf.WaitForState() + outputRaw, err := stateConf.WaitForStateContext(ctx) if _, ok := outputRaw.(*lightsail.GetRelationalDatabaseOutput); ok { return err diff --git a/website/docs/r/lightsail_database.html.markdown b/website/docs/r/lightsail_database.html.markdown index ac3ca5dde245..9608a5a9a764 100644 --- a/website/docs/r/lightsail_database.html.markdown +++ b/website/docs/r/lightsail_database.html.markdown @@ -187,6 +187,15 @@ In addition to all arguments above, the following attributes are exported: * `support_code` - The support code for the database. Include this code in your email to support when you have questions about a database in Lightsail. This code enables our support team to look up your Lightsail information more easily. * `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). +## Timeouts + +[Configuration options](https://www.terraform.io/docs/configuration/blocks/resources/syntax.html#operation-timeouts): + +* `create` - (Default `30m`) +* `read` - (Default `30m`) +* `update` - (Default `30m`) +* `delete` - (Default `30m`) + ## Import Lightsail Databases can be imported using their name, e.g. From 7ef42997314f96e1e4354e2692d0e00d0c9654dc Mon Sep 17 00:00:00 2001 From: Dennis Pattmann Date: Thu, 25 Aug 2022 22:21:18 +0200 Subject: [PATCH 03/13] Added changelog file --- .changelog/26488.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/26488.txt diff --git a/.changelog/26488.txt b/.changelog/26488.txt new file mode 100644 index 000000000000..197bbb1967ca --- /dev/null +++ b/.changelog/26488.txt @@ -0,0 +1,7 @@ +```release-note:bug +resource/aws_lightsail_database: The `availability_zone` attribute is now optional/computed to support HA bundle_ids +``` + +```release-note:enhancement +resource/aws_lightsail_database: Add configurable timeouts +``` \ No newline at end of file From 518995b464a4d092fe73baada3ebd35d333122a7 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Tue, 27 Dec 2022 11:53:37 -0500 Subject: [PATCH 04/13] lightsail: wait, new waitOperationWithContext --- internal/service/lightsail/wait.go | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/internal/service/lightsail/wait.go b/internal/service/lightsail/wait.go index 7795a3bd147e..cc232903cb55 100644 --- a/internal/service/lightsail/wait.go +++ b/internal/service/lightsail/wait.go @@ -34,8 +34,8 @@ const ( DatabaseMinTimeout = 3 * time.Second ) -// waitOperation waits for an Operation to return Succeeded or Compleated -func waitOperation(ctx context.Context, conn *lightsail.Lightsail, oid *string) error { +// waitOperation waits for an Operation to return Succeeded or Completed +func waitOperation(conn *lightsail.Lightsail, oid *string) error { stateConf := &resource.StateChangeConf{ Pending: []string{lightsail.OperationStatusStarted}, Target: []string{lightsail.OperationStatusCompleted, lightsail.OperationStatusSucceeded}, @@ -45,7 +45,7 @@ func waitOperation(ctx context.Context, conn *lightsail.Lightsail, oid *string) MinTimeout: OperationMinTimeout, } - outputRaw, err := stateConf.WaitForStateContext(ctx) + outputRaw, err := stateConf.WaitForState() if _, ok := outputRaw.(*lightsail.GetOperationOutput); ok { return err @@ -228,3 +228,23 @@ func waitInstanceStateWithContext(ctx context.Context, conn *lightsail.Lightsail return nil, err } + +// waitOperation waits for an Operation to return Succeeded or Completed with context +func waitOperationWithContext(ctx context.Context, conn *lightsail.Lightsail, oid *string) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{lightsail.OperationStatusStarted}, + Target: []string{lightsail.OperationStatusCompleted, lightsail.OperationStatusSucceeded}, + Refresh: statusOperation(conn, oid), + Timeout: OperationTimeout, + Delay: OperationDelay, + MinTimeout: OperationMinTimeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if _, ok := outputRaw.(*lightsail.GetOperationOutput); ok { + return err + } + + return err +} From 35365f3c5e263a21467193e33d9010fbc9c6ae0a Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Tue, 27 Dec 2022 11:54:13 -0500 Subject: [PATCH 05/13] lightsail: database move to waitOperationWithContext --- internal/service/lightsail/database.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/lightsail/database.go b/internal/service/lightsail/database.go index 3ba9c422a7cc..d55ba116ac59 100644 --- a/internal/service/lightsail/database.go +++ b/internal/service/lightsail/database.go @@ -236,7 +236,7 @@ func resourceDatabaseCreate(ctx context.Context, d *schema.ResourceData, meta in op := resp.Operations[0] d.SetId(d.Get("relational_database_name").(string)) - err = waitOperation(ctx, conn, op.Id) + err = waitOperationWithContext(ctx, conn, op.Id) if err != nil { return diag.Errorf("Error waiting for Relational Database (%s) to become ready: %s", d.Id(), err) } @@ -262,7 +262,7 @@ func resourceDatabaseCreate(ctx context.Context, d *schema.ResourceData, meta in op := resp.Operations[0] - err = waitOperation(ctx, conn, op.Id) + err = waitOperationWithContext(ctx, conn, op.Id) if err != nil { return diag.Errorf("Error waiting for Relational Database (%s) to become ready: %s", d.Id(), err) } @@ -372,7 +372,7 @@ func resourceDatabaseDelete(ctx context.Context, d *schema.ResourceData, meta in op := resp.Operations[0] - err = waitOperation(ctx, conn, op.Id) + err = waitOperationWithContext(ctx, conn, op.Id) if err != nil { return diag.Errorf("Error waiting for Relational Database (%s) to Delete: %s", d.Id(), err) } @@ -459,7 +459,7 @@ func resourceDatabaseUpdate(ctx context.Context, d *schema.ResourceData, meta in op := resp.Operations[0] - err = waitOperation(ctx, conn, op.Id) + err = waitOperationWithContext(ctx, conn, op.Id) if err != nil { return diag.Errorf("Error waiting for Relational Database (%s) to become ready: %s", d.Id(), err) } From 481666d77650d94af7cbada1030a3f1561459ea9 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Tue, 27 Dec 2022 11:54:26 -0500 Subject: [PATCH 06/13] lightsail: Add database ha tests --- internal/service/lightsail/database_test.go | 79 +++++++++++++++++---- 1 file changed, 67 insertions(+), 12 deletions(-) diff --git a/internal/service/lightsail/database_test.go b/internal/service/lightsail/database_test.go index 32dbc821ecc6..7b23b0c08362 100644 --- a/internal/service/lightsail/database_test.go +++ b/internal/service/lightsail/database_test.go @@ -24,7 +24,7 @@ import ( func TestAccLightsailDatabase_basic(t *testing.T) { var db lightsail.RelationalDatabase resourceName := "aws_lightsail_database.test" - rName := fmt.Sprintf("tf-test-lightsail-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { @@ -76,7 +76,7 @@ func TestAccLightsailDatabase_basic(t *testing.T) { func TestAccLightsailDatabase_RelationalDatabaseName(t *testing.T) { var db lightsail.RelationalDatabase resourceName := "aws_lightsail_database.test" - rName := fmt.Sprintf("tf-test-lightsail-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) rNameTooShort := "s" rNameTooLong := fmt.Sprintf("%s-%s", rName, sdkacctest.RandString(255)) rNameContainsUnderscore := fmt.Sprintf("%s-%s", rName, "_test") @@ -137,7 +137,7 @@ func TestAccLightsailDatabase_RelationalDatabaseName(t *testing.T) { func TestAccLightsailDatabase_MasterDatabaseName(t *testing.T) { var db lightsail.RelationalDatabase - rName := fmt.Sprintf("tf-test-lightsail-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" dbName := "randomdatabasename" dbNameTooShort := "" @@ -203,7 +203,7 @@ func TestAccLightsailDatabase_MasterDatabaseName(t *testing.T) { func TestAccLightsailDatabase_MasterUsername(t *testing.T) { var db lightsail.RelationalDatabase - rName := fmt.Sprintf("tf-test-lightsail-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" username := "username1" usernameTooShort := "" @@ -273,7 +273,7 @@ func TestAccLightsailDatabase_MasterUsername(t *testing.T) { } func TestAccLightsailDatabase_MasterPassword(t *testing.T) { - rName := fmt.Sprintf("tf-test-lightsail-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) password := "testpassword" passwordTooShort := "short" passwordTooLong := fmt.Sprintf("%s-%s", password, sdkacctest.RandString(128)) @@ -322,7 +322,7 @@ func TestAccLightsailDatabase_MasterPassword(t *testing.T) { func TestAccLightsailDatabase_PreferredBackupWindow(t *testing.T) { var db lightsail.RelationalDatabase - rName := fmt.Sprintf("tf-test-lightsail-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" backupWindowInvalidHour := "25:30-10:00" backupWindowInvalidMinute := "10:00-10:70" @@ -376,7 +376,7 @@ func TestAccLightsailDatabase_PreferredBackupWindow(t *testing.T) { func TestAccLightsailDatabase_PreferredMaintenanceWindow(t *testing.T) { var db lightsail.RelationalDatabase - rName := fmt.Sprintf("tf-test-lightsail-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" maintenanceWindowInvalidDay := "tuesday:04:30-tue:05:00" maintenanceWindowInvalidHour := "tue:04:30-tue:30:00" @@ -435,7 +435,7 @@ func TestAccLightsailDatabase_PreferredMaintenanceWindow(t *testing.T) { func TestAccLightsailDatabase_PubliclyAccessible(t *testing.T) { var db lightsail.RelationalDatabase - rName := fmt.Sprintf("tf-test-lightsail-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" resource.ParallelTest(t, resource.TestCase{ @@ -479,7 +479,7 @@ func TestAccLightsailDatabase_PubliclyAccessible(t *testing.T) { func TestAccLightsailDatabase_BackupRetentionEnabled(t *testing.T) { var db lightsail.RelationalDatabase - rName := fmt.Sprintf("tf-test-lightsail-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" resource.ParallelTest(t, resource.TestCase{ @@ -523,7 +523,7 @@ func TestAccLightsailDatabase_BackupRetentionEnabled(t *testing.T) { func TestAccLightsailDatabase_FinalSnapshotName(t *testing.T) { var db lightsail.RelationalDatabase - rName := fmt.Sprintf("tf-test-lightsail-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" sName := fmt.Sprintf("%s-snapshot", rName) sNameTooShort := "s" @@ -580,7 +580,7 @@ func TestAccLightsailDatabase_FinalSnapshotName(t *testing.T) { func TestAccLightsailDatabase_Tags(t *testing.T) { var db1, db2, db3 lightsail.RelationalDatabase - rName := fmt.Sprintf("tf-test-lightsail-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" resource.ParallelTest(t, resource.TestCase{ @@ -633,9 +633,48 @@ func TestAccLightsailDatabase_Tags(t *testing.T) { }) } +func TestAccLightsailDatabase_ha(t *testing.T) { + var db lightsail.RelationalDatabase + resourceName := "aws_lightsail_database.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(lightsail.EndpointsID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, lightsail.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDatabaseDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDatabaseConfig_ha(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDatabaseExists(resourceName, &db), + resource.TestCheckResourceAttr(resourceName, "relational_database_name", rName), + resource.TestCheckResourceAttr(resourceName, "bundle_id", "micro_ha_1_0"), + resource.TestCheckResourceAttrSet(resourceName, "availability_zone"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "apply_immediately", + "master_password", + "skip_final_snapshot", + "final_snapshot_name", + }, + }, + }, + }) +} + func TestAccLightsailDatabase_disappears(t *testing.T) { var db lightsail.RelationalDatabase - rName := fmt.Sprintf("tf-test-lightsail-%d", sdkacctest.RandInt()) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" testDestroy := func(*terraform.State) error { @@ -996,3 +1035,19 @@ resource "aws_lightsail_database" "test" { } `, rName, tagKey1, tagValue1, tagKey2, tagValue2)) } + +func testAccDatabaseConfig_ha(rName string) string { + return acctest.ConfigCompose( + testAccDatabaseConfigBase(), + fmt.Sprintf(` +resource "aws_lightsail_database" "test" { + relational_database_name = %[1]q + master_database_name = "testdatabasename" + master_password = "testdatabasepassword" + master_username = "test" + blueprint_id = "mysql_8_0" + bundle_id = "micro_ha_1_0" + skip_final_snapshot = true +} +`, rName)) +} From ab3fc36530ab3edff492d2e3031edc1a29ae6b94 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Tue, 27 Dec 2022 12:01:29 -0500 Subject: [PATCH 07/13] changelog: update PR number --- .changelog/{26488.txt => 28590.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .changelog/{26488.txt => 28590.txt} (100%) diff --git a/.changelog/26488.txt b/.changelog/28590.txt similarity index 100% rename from .changelog/26488.txt rename to .changelog/28590.txt From 2f8738cb358be31f3672be12cdb2486d5c34993e Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Tue, 27 Dec 2022 12:38:14 -0500 Subject: [PATCH 08/13] lightsail: Database, semgrep and WithoutTimeout --- internal/service/lightsail/database.go | 14 ++++--------- internal/service/lightsail/database_test.go | 20 +++++++++---------- .../docs/r/lightsail_database.html.markdown | 9 --------- 3 files changed, 14 insertions(+), 29 deletions(-) diff --git a/internal/service/lightsail/database.go b/internal/service/lightsail/database.go index d55ba116ac59..94f956bfd939 100644 --- a/internal/service/lightsail/database.go +++ b/internal/service/lightsail/database.go @@ -23,10 +23,10 @@ const ( func ResourceDatabase() *schema.Resource { return &schema.Resource{ - CreateContext: resourceDatabaseCreate, - ReadContext: resourceDatabaseRead, - UpdateContext: resourceDatabaseUpdate, - DeleteContext: resourceDatabaseDelete, + CreateWithoutTimeout: resourceDatabaseCreate, + ReadWithoutTimeout: resourceDatabaseRead, + UpdateWithoutTimeout: resourceDatabaseUpdate, + DeleteWithoutTimeout: resourceDatabaseDelete, Importer: &schema.ResourceImporter{ StateContext: ResourceDatabaseImport, }, @@ -177,12 +177,6 @@ func ResourceDatabase() *schema.Resource { "tags": tftags.TagsSchema(), "tags_all": tftags.TagsSchemaComputed(), }, - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(30 * time.Minute), - Read: schema.DefaultTimeout(30 * time.Minute), - Update: schema.DefaultTimeout(30 * time.Minute), - Delete: schema.DefaultTimeout(30 * time.Minute), - }, CustomizeDiff: verify.SetTagsDiff, } } diff --git a/internal/service/lightsail/database_test.go b/internal/service/lightsail/database_test.go index 7b23b0c08362..7cc17ccc4d75 100644 --- a/internal/service/lightsail/database_test.go +++ b/internal/service/lightsail/database_test.go @@ -73,7 +73,7 @@ func TestAccLightsailDatabase_basic(t *testing.T) { }) } -func TestAccLightsailDatabase_RelationalDatabaseName(t *testing.T) { +func TestAccLightsailDatabase_relationalDatabaseName(t *testing.T) { var db lightsail.RelationalDatabase resourceName := "aws_lightsail_database.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -135,7 +135,7 @@ func TestAccLightsailDatabase_RelationalDatabaseName(t *testing.T) { }) } -func TestAccLightsailDatabase_MasterDatabaseName(t *testing.T) { +func TestAccLightsailDatabase_masterDatabaseName(t *testing.T) { var db lightsail.RelationalDatabase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" @@ -201,7 +201,7 @@ func TestAccLightsailDatabase_MasterDatabaseName(t *testing.T) { }) } -func TestAccLightsailDatabase_MasterUsername(t *testing.T) { +func TestAccLightsailDatabase_masterUsername(t *testing.T) { var db lightsail.RelationalDatabase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" @@ -272,7 +272,7 @@ func TestAccLightsailDatabase_MasterUsername(t *testing.T) { }) } -func TestAccLightsailDatabase_MasterPassword(t *testing.T) { +func TestAccLightsailDatabase_masterPassword(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) password := "testpassword" passwordTooShort := "short" @@ -320,7 +320,7 @@ func TestAccLightsailDatabase_MasterPassword(t *testing.T) { }) } -func TestAccLightsailDatabase_PreferredBackupWindow(t *testing.T) { +func TestAccLightsailDatabase_preferredBackupWindow(t *testing.T) { var db lightsail.RelationalDatabase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" @@ -374,7 +374,7 @@ func TestAccLightsailDatabase_PreferredBackupWindow(t *testing.T) { }) } -func TestAccLightsailDatabase_PreferredMaintenanceWindow(t *testing.T) { +func TestAccLightsailDatabase_preferredMaintenanceWindow(t *testing.T) { var db lightsail.RelationalDatabase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" @@ -433,7 +433,7 @@ func TestAccLightsailDatabase_PreferredMaintenanceWindow(t *testing.T) { }) } -func TestAccLightsailDatabase_PubliclyAccessible(t *testing.T) { +func TestAccLightsailDatabase_publiclyAccessible(t *testing.T) { var db lightsail.RelationalDatabase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" @@ -477,7 +477,7 @@ func TestAccLightsailDatabase_PubliclyAccessible(t *testing.T) { }) } -func TestAccLightsailDatabase_BackupRetentionEnabled(t *testing.T) { +func TestAccLightsailDatabase_backupRetentionEnabled(t *testing.T) { var db lightsail.RelationalDatabase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" @@ -521,7 +521,7 @@ func TestAccLightsailDatabase_BackupRetentionEnabled(t *testing.T) { }) } -func TestAccLightsailDatabase_FinalSnapshotName(t *testing.T) { +func TestAccLightsailDatabase_finalSnapshotName(t *testing.T) { var db lightsail.RelationalDatabase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" @@ -578,7 +578,7 @@ func TestAccLightsailDatabase_FinalSnapshotName(t *testing.T) { }) } -func TestAccLightsailDatabase_Tags(t *testing.T) { +func TestAccLightsailDatabase_tags(t *testing.T) { var db1, db2, db3 lightsail.RelationalDatabase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_lightsail_database.test" diff --git a/website/docs/r/lightsail_database.html.markdown b/website/docs/r/lightsail_database.html.markdown index 1a039debdd95..6ea016b7ec2a 100644 --- a/website/docs/r/lightsail_database.html.markdown +++ b/website/docs/r/lightsail_database.html.markdown @@ -184,15 +184,6 @@ In addition to all arguments above, the following attributes are exported: * `support_code` - The support code for the database. Include this code in your email to support when you have questions about a database in Lightsail. This code enables our support team to look up your Lightsail information more easily. * `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). -## Timeouts - -[Configuration options](https://www.terraform.io/docs/configuration/blocks/resources/syntax.html#operation-timeouts): - -* `create` - (Default `30m`) -* `read` - (Default `30m`) -* `update` - (Default `30m`) -* `delete` - (Default `30m`) - ## Import Lightsail Databases can be imported using their name, e.g. From 4b60feb1b19bef6f0a49f394dfcd1d9ea9261cc1 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Tue, 27 Dec 2022 12:40:25 -0500 Subject: [PATCH 09/13] changelog: update changelog to reflect WithoutTimeout --- .changelog/28590.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/28590.txt b/.changelog/28590.txt index 197bbb1967ca..5a72f1bf1f6f 100644 --- a/.changelog/28590.txt +++ b/.changelog/28590.txt @@ -3,5 +3,5 @@ resource/aws_lightsail_database: The `availability_zone` attribute is now option ``` ```release-note:enhancement -resource/aws_lightsail_database: Add configurable timeouts +resource/aws_lightsail_database: Update Resource functions to use WithoutTimeout CRUD handlers ``` \ No newline at end of file From 1fb68a794ada4aca871c67b8a3cda115a594d005 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Tue, 27 Dec 2022 13:27:00 -0500 Subject: [PATCH 10/13] lightsail: Amend wait, increase timeout --- internal/service/lightsail/wait.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/service/lightsail/wait.go b/internal/service/lightsail/wait.go index cc232903cb55..d13f4b5e9e0e 100644 --- a/internal/service/lightsail/wait.go +++ b/internal/service/lightsail/wait.go @@ -14,11 +14,11 @@ import ( ) const ( - // OperationTimeout is the Timout Value for Operations - OperationTimeout = 20 * time.Minute + // OperationTimeout is the Timeout Value for Operations + OperationTimeout = 30 * time.Minute // OperationDelay is the Delay Value for Operations OperationDelay = 5 * time.Second - // OperationMinTimeout is the MinTimout Value for Operations + // OperationMinTimeout is the MinTimeout Value for Operations OperationMinTimeout = 3 * time.Second // DatabaseStateModifying is a state value for a Relational Database undergoing a modification @@ -26,11 +26,11 @@ const ( // DatabaseStateAvailable is a state value for a Relational Database available for modification DatabaseStateAvailable = "available" - // DatabaseTimeout is the Timout Value for Relational Database Modifications - DatabaseTimeout = 20 * time.Minute + // DatabaseTimeout is the Timeout Value for Relational Database Modifications + DatabaseTimeout = 30 * time.Minute // DatabaseDelay is the Delay Value for Relational Database Modifications DatabaseDelay = 5 * time.Second - // DatabaseMinTimeout is the MinTimout Value for Relational Database Modifications + // DatabaseMinTimeout is the MinTimeout Value for Relational Database Modifications DatabaseMinTimeout = 3 * time.Second ) From 299d5c0910992c1f9b9a616fcb90346db60ac307 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 Jan 2023 09:40:01 -0500 Subject: [PATCH 11/13] Tweak CHANGELOG entry. --- .changelog/28590.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.changelog/28590.txt b/.changelog/28590.txt index 5a72f1bf1f6f..d445ceabaccf 100644 --- a/.changelog/28590.txt +++ b/.changelog/28590.txt @@ -1,7 +1,3 @@ ```release-note:bug -resource/aws_lightsail_database: The `availability_zone` attribute is now optional/computed to support HA bundle_ids -``` - -```release-note:enhancement -resource/aws_lightsail_database: Update Resource functions to use WithoutTimeout CRUD handlers +resource/aws_lightsail_database: The `availability_zone` attribute is now optional/computed to support HA `bundle_id`s ``` \ No newline at end of file From 95a773bca6685fefd44d66b945429a1b6d9c9bf1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 Jan 2023 12:16:02 -0500 Subject: [PATCH 12/13] r/aws_lightsail_database: Cosmetics. --- internal/service/lightsail/database.go | 259 +++++++++----------- internal/service/lightsail/database_test.go | 53 ++-- 2 files changed, 132 insertions(+), 180 deletions(-) diff --git a/internal/service/lightsail/database.go b/internal/service/lightsail/database.go index 94f956bfd939..f49054d3e9f8 100644 --- a/internal/service/lightsail/database.go +++ b/internal/service/lightsail/database.go @@ -27,8 +27,9 @@ func ResourceDatabase() *schema.Resource { ReadWithoutTimeout: resourceDatabaseRead, UpdateWithoutTimeout: resourceDatabaseUpdate, DeleteWithoutTimeout: resourceDatabaseDelete, + Importer: &schema.ResourceImporter{ - StateContext: ResourceDatabaseImport, + StateContext: resourceDatabaseImport, }, Schema: map[string]*schema.Schema{ @@ -186,91 +187,78 @@ func resourceDatabaseCreate(ctx context.Context, d *schema.ResourceData, meta in defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{}))) - req := lightsail.CreateRelationalDatabaseInput{ + relationalDatabaseName := d.Get("relational_database_name").(string) + input := &lightsail.CreateRelationalDatabaseInput{ MasterDatabaseName: aws.String(d.Get("master_database_name").(string)), MasterUsername: aws.String(d.Get("master_username").(string)), RelationalDatabaseBlueprintId: aws.String(d.Get("blueprint_id").(string)), RelationalDatabaseBundleId: aws.String(d.Get("bundle_id").(string)), - RelationalDatabaseName: aws.String(d.Get("relational_database_name").(string)), + RelationalDatabaseName: aws.String(relationalDatabaseName), } if v, ok := d.GetOk("availability_zone"); ok { - req.AvailabilityZone = aws.String(v.(string)) + input.AvailabilityZone = aws.String(v.(string)) } if v, ok := d.GetOk("master_password"); ok { - req.MasterUserPassword = aws.String(v.(string)) + input.MasterUserPassword = aws.String(v.(string)) } if v, ok := d.GetOk("preferred_backup_window"); ok { - req.PreferredBackupWindow = aws.String(v.(string)) + input.PreferredBackupWindow = aws.String(v.(string)) } if v, ok := d.GetOk("preferred_maintenance_window"); ok { - req.PreferredMaintenanceWindow = aws.String(v.(string)) + input.PreferredMaintenanceWindow = aws.String(v.(string)) } if v, ok := d.GetOk("publicly_accessible"); ok { - req.PubliclyAccessible = aws.Bool(v.(bool)) + input.PubliclyAccessible = aws.Bool(v.(bool)) } if len(tags) > 0 { - req.Tags = Tags(tags.IgnoreAWS()) + input.Tags = Tags(tags.IgnoreAWS()) } - resp, err := conn.CreateRelationalDatabaseWithContext(ctx, &req) - if err != nil { - return diag.FromErr(err) - } + output, err := conn.CreateRelationalDatabaseWithContext(ctx, input) - if len(resp.Operations) == 0 { - return diag.Errorf("No operations found for Create Relational Database request") + if err != nil { + return diag.Errorf("creating Lightsail Relational Database (%s): %s", relationalDatabaseName, err) } - op := resp.Operations[0] - d.SetId(d.Get("relational_database_name").(string)) + d.SetId(relationalDatabaseName) - err = waitOperationWithContext(ctx, conn, op.Id) - if err != nil { - return diag.Errorf("Error waiting for Relational Database (%s) to become ready: %s", d.Id(), err) + if err := waitOperationWithContext(ctx, conn, output.Operations[0].Id); err != nil { + return diag.Errorf("waiting for Lightsail Relational Database (%s) create: %s", d.Id(), err) } // Backup Retention is not a value you can pass on creation and defaults to true. // Forcing an update of the value after creation if the backup_retention_enabled value is false. - if v := d.Get("backup_retention_enabled"); v == false { - log.Printf("[DEBUG] Lightsail Database (%s) backup_retention_enabled setting is false. Updating value.", d.Id()) - req := lightsail.UpdateRelationalDatabaseInput{ + if !d.Get("backup_retention_enabled").(bool) { + input := &lightsail.UpdateRelationalDatabaseInput{ ApplyImmediately: aws.Bool(true), - RelationalDatabaseName: aws.String(d.Id()), DisableBackupRetention: aws.Bool(true), + RelationalDatabaseName: aws.String(d.Id()), } - resp, err := conn.UpdateRelationalDatabaseWithContext(ctx, &req) + output, err := conn.UpdateRelationalDatabaseWithContext(ctx, input) + if err != nil { - return diag.FromErr(err) + return diag.Errorf("updating Lightsail Relational Database (%s) backup retention: %s", d.Id(), err) } - if len(resp.Operations) == 0 { - return diag.Errorf("No operations found for Update Relational Database request") + if err := waitOperationWithContext(ctx, conn, output.Operations[0].Id); err != nil { + return diag.Errorf("waiting for Lightsail Relational Database (%s) update: %s", d.Id(), err) } - op := resp.Operations[0] - - err = waitOperationWithContext(ctx, conn, op.Id) - if err != nil { - return diag.Errorf("Error waiting for Relational Database (%s) to become ready: %s", d.Id(), err) - } - - err = waitDatabaseBackupRetentionModified(ctx, conn, aws.String(d.Id()), aws.Bool(v.(bool))) - if err != nil { - return diag.Errorf("Error waiting for Relational Database (%s) Backup Retention to be updated: %s", d.Id(), err) + if err := waitDatabaseBackupRetentionModified(ctx, conn, aws.String(d.Id()), false); err != nil { + return diag.Errorf("waiting for Lightsail Relational Database (%s) backup retention update: %s", d.Id(), err) } } // Some Operations can complete before the Database enters the Available state. Added a waiter to make sure the Database is available before continuing. - _, err = waitDatabaseModified(ctx, conn, aws.String(d.Id())) - if err != nil { - return diag.Errorf("Error waiting for Relational Database (%s) to become available: %s", d.Id(), err) + if _, err = waitDatabaseModified(ctx, conn, aws.String(d.Id())); err != nil { + return diag.Errorf("waiting for Lightsail Relational Database (%s) to become available: %s", d.Id(), err) } return resourceDatabaseRead(ctx, d, meta) @@ -292,7 +280,7 @@ func resourceDatabaseRead(ctx context.Context, d *schema.ResourceData, meta inte } if err != nil { - return diag.Errorf("error reading LightSail Relational Database (%s): %s", d.Id(), err) + return diag.Errorf("reading Lightsail Relational Database (%s): %s", d.Id(), err) } rd := database.RelationalDatabase @@ -324,153 +312,126 @@ func resourceDatabaseRead(ctx context.Context, d *schema.ResourceData, meta inte //lintignore:AWSR002 if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { - return diag.Errorf("error setting tags: %s", err) + return diag.Errorf("setting tags: %s", err) } if err := d.Set("tags_all", tags.Map()); err != nil { - return diag.Errorf("error setting tags_all: %s", err) + return diag.Errorf("setting tags_all: %s", err) } return nil } -func resourceDatabaseDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceDatabaseUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).LightsailConn() - // Some Operations can complete before the Database enters the Available state. Added a waiter to make sure the Database is available before continuing. - _, err := waitDatabaseModified(ctx, conn, aws.String(d.Id())) - if err != nil { - return diag.Errorf("Error waiting for Relational Database (%s) to become available: %s", d.Id(), err) - } + if d.HasChangesExcept("apply_immediately", "final_snapshot_name", "skip_final_snapshot", "tags", "tags_all") { + input := &lightsail.UpdateRelationalDatabaseInput{ + ApplyImmediately: aws.Bool(d.Get("apply_immediately").(bool)), + RelationalDatabaseName: aws.String(d.Id()), + } - skipFinalSnapshot := d.Get("skip_final_snapshot").(bool) + if d.HasChange("backup_retention_enabled") { + if d.Get("backup_retention_enabled").(bool) { + input.EnableBackupRetention = aws.Bool(d.Get("backup_retention_enabled").(bool)) + } else { + input.DisableBackupRetention = aws.Bool(true) + } + } - req := lightsail.DeleteRelationalDatabaseInput{ - RelationalDatabaseName: aws.String(d.Id()), - SkipFinalSnapshot: aws.Bool(skipFinalSnapshot), - } + if d.HasChange("ca_certificate_identifier") { + input.CaCertificateIdentifier = aws.String(d.Get("ca_certificate_identifier").(string)) + } - if !skipFinalSnapshot { - if name, present := d.GetOk("final_snapshot_name"); present { - req.FinalRelationalDatabaseSnapshotName = aws.String(name.(string)) - } else { - return diag.Errorf("Lightsail Database FinalRelationalDatabaseSnapshotName is required when a final snapshot is required") + if d.HasChange("master_password") { + input.MasterUserPassword = aws.String(d.Get("master_password").(string)) } - } - resp, err := conn.DeleteRelationalDatabaseWithContext(ctx, &req) + if d.HasChange("preferred_backup_window") { + input.PreferredBackupWindow = aws.String(d.Get("preferred_backup_window").(string)) + } - if err != nil { - return diag.FromErr(err) - } + if d.HasChange("preferred_maintenance_window") { + input.PreferredMaintenanceWindow = aws.String(d.Get("preferred_maintenance_window").(string)) + } - op := resp.Operations[0] + if d.HasChange("publicly_accessible") { + input.PubliclyAccessible = aws.Bool(d.Get("publicly_accessible").(bool)) + } - err = waitOperationWithContext(ctx, conn, op.Id) - if err != nil { - return diag.Errorf("Error waiting for Relational Database (%s) to Delete: %s", d.Id(), err) - } + output, err := conn.UpdateRelationalDatabaseWithContext(ctx, input) - return nil -} + if err != nil { + return diag.Errorf("updating Lightsail Relational Database (%s): %s", d.Id(), err) + } -func ResourceDatabaseImport( - ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - // Neither skip_final_snapshot nor final_snapshot_identifier can be fetched - // from any API call, so we need to default skip_final_snapshot to true so - // that final_snapshot_identifier is not required - d.Set("skip_final_snapshot", true) - return []*schema.ResourceData{d}, nil -} + if err := waitOperationWithContext(ctx, conn, output.Operations[0].Id); err != nil { + return diag.Errorf("waiting for Lightsail Relational Database (%s) update: %s", d.Id(), err) + } -func resourceDatabaseUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - conn := meta.(*conns.AWSClient).LightsailConn() - requestUpdate := false + if d.HasChange("backup_retention_enabled") { + if err := waitDatabaseBackupRetentionModified(ctx, conn, aws.String(d.Id()), d.Get("backup_retention_enabled").(bool)); err != nil { + return diag.Errorf("waiting for Lightsail Relational Database (%s) backup retention update: %s", d.Id(), err) + } + } - req := lightsail.UpdateRelationalDatabaseInput{ - ApplyImmediately: aws.Bool(d.Get("apply_immediately").(bool)), - RelationalDatabaseName: aws.String(d.Id()), + // Some Operations can complete before the Database enters the Available state. Added a waiter to make sure the Database is available before continuing. + if _, err = waitDatabaseModified(ctx, conn, aws.String(d.Id())); err != nil { + return diag.Errorf("waiting for Lightsail Relational Database (%s) to become available: %s", d.Id(), err) + } } - if d.HasChange("ca_certificate_identifier") { - req.CaCertificateIdentifier = aws.String(d.Get("ca_certificate_identifier").(string)) - requestUpdate = true - } + if d.HasChange("tags_all") { + o, n := d.GetChange("tags_all") - if d.HasChange("backup_retention_enabled") { - if d.Get("backup_retention_enabled").(bool) { - req.EnableBackupRetention = aws.Bool(d.Get("backup_retention_enabled").(bool)) - } else { - req.DisableBackupRetention = aws.Bool(true) + if err := UpdateTagsWithContext(ctx, conn, d.Id(), o, n); err != nil { + return diag.Errorf("updating Lightsail Relational Database (%s) tags: %s", d.Id(), err) } - requestUpdate = true - } - - if d.HasChange("master_password") { - req.MasterUserPassword = aws.String(d.Get("master_password").(string)) - requestUpdate = true } - if d.HasChange("preferred_backup_window") { - req.PreferredBackupWindow = aws.String(d.Get("preferred_backup_window").(string)) - requestUpdate = true - } + return resourceDatabaseRead(ctx, d, meta) +} - if d.HasChange("preferred_maintenance_window") { - req.PreferredMaintenanceWindow = aws.String(d.Get("preferred_maintenance_window").(string)) - requestUpdate = true - } +func resourceDatabaseDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).LightsailConn() - if d.HasChange("publicly_accessible") { - req.PubliclyAccessible = aws.Bool(d.Get("publicly_accessible").(bool)) - requestUpdate = true + // Some Operations can complete before the Database enters the Available state. Added a waiter to make sure the Database is available before continuing. + if _, err := waitDatabaseModified(ctx, conn, aws.String(d.Id())); err != nil { + return diag.Errorf("waiting for Lightsail Relational Database (%s) to become available: %s", d.Id(), err) } - if d.HasChange("tags") { - o, n := d.GetChange("tags") + skipFinalSnapshot := d.Get("skip_final_snapshot").(bool) - if err := UpdateTagsWithContext(ctx, conn, d.Id(), o, n); err != nil { - return diag.Errorf("error updating Lightsail Database (%s) tags: %s", d.Id(), err) - } + input := &lightsail.DeleteRelationalDatabaseInput{ + RelationalDatabaseName: aws.String(d.Id()), + SkipFinalSnapshot: aws.Bool(skipFinalSnapshot), } - if d.HasChange("tags_all") { - o, n := d.GetChange("tags_all") - if err := UpdateTagsWithContext(ctx, conn, d.Id(), o, n); err != nil { - return diag.Errorf("error updating Lightsail Database (%s) tags: %s", d.Id(), err) + if !skipFinalSnapshot { + if name, present := d.GetOk("final_snapshot_name"); present { + input.FinalRelationalDatabaseSnapshotName = aws.String(name.(string)) + } else { + return diag.Errorf("Lightsail Database FinalRelationalDatabaseSnapshotName is required when a final snapshot is required") } } - if requestUpdate { - resp, err := conn.UpdateRelationalDatabaseWithContext(ctx, &req) - if err != nil { - return diag.FromErr(err) - } - - if len(resp.Operations) == 0 { - return diag.Errorf("No operations found for Update Relational Database request") - } - - op := resp.Operations[0] + output, err := conn.DeleteRelationalDatabaseWithContext(ctx, input) - err = waitOperationWithContext(ctx, conn, op.Id) - if err != nil { - return diag.Errorf("Error waiting for Relational Database (%s) to become ready: %s", d.Id(), err) - } - - if d.HasChange("backup_retention_enabled") { - err = waitDatabaseBackupRetentionModified(ctx, conn, aws.String(d.Id()), aws.Bool(d.Get("backup_retention_enabled").(bool))) - if err != nil { - return diag.Errorf("Error waiting for Relational Database (%s) Backup Retention to be updated: %s", d.Id(), err) - } - } + if err != nil { + return diag.Errorf("deleting Lightsail Relational Database (%s): %s", d.Id(), err) + } - // Some Operations can complete before the Database enters the Available state. Added a waiter to make sure the Database is available before continuing. - _, err = waitDatabaseModified(ctx, conn, aws.String(d.Id())) - if err != nil { - return diag.Errorf("Error waiting for Relational Database (%s) to become available: %s", d.Id(), err) - } + if err := waitOperationWithContext(ctx, conn, output.Operations[0].Id); err != nil { + return diag.Errorf("waiting for Lightsail Relational Database (%s) delete: %s", d.Id(), err) } - return resourceDatabaseRead(ctx, d, meta) + return nil +} + +func resourceDatabaseImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + // Neither skip_final_snapshot nor final_snapshot_identifier can be fetched + // from any API call, so we need to default skip_final_snapshot to true so + // that final_snapshot_identifier is not required + d.Set("skip_final_snapshot", true) + return []*schema.ResourceData{d}, nil } diff --git a/internal/service/lightsail/database_test.go b/internal/service/lightsail/database_test.go index 7cc17ccc4d75..bfd9a7e1bbb3 100644 --- a/internal/service/lightsail/database_test.go +++ b/internal/service/lightsail/database_test.go @@ -449,7 +449,7 @@ func TestAccLightsailDatabase_publiclyAccessible(t *testing.T) { CheckDestroy: testAccCheckDatabaseDestroy, Steps: []resource.TestStep{ { - Config: testAccDatabaseConfig_publiclyAccessible(rName, "true"), + Config: testAccDatabaseConfig_publiclyAccessible(rName, true), Check: resource.ComposeTestCheckFunc( testAccCheckDatabaseExists(resourceName, &db), resource.TestCheckResourceAttr(resourceName, "publicly_accessible", "true"), @@ -467,7 +467,7 @@ func TestAccLightsailDatabase_publiclyAccessible(t *testing.T) { }, }, { - Config: testAccDatabaseConfig_publiclyAccessible(rName, "false"), + Config: testAccDatabaseConfig_publiclyAccessible(rName, false), Check: resource.ComposeTestCheckFunc( testAccCheckDatabaseExists(resourceName, &db), resource.TestCheckResourceAttr(resourceName, "publicly_accessible", "false"), @@ -493,7 +493,7 @@ func TestAccLightsailDatabase_backupRetentionEnabled(t *testing.T) { CheckDestroy: testAccCheckDatabaseDestroy, Steps: []resource.TestStep{ { - Config: testAccDatabaseConfig_backupRetentionEnabled(rName, "true"), + Config: testAccDatabaseConfig_backupRetentionEnabled(rName, true), Check: resource.ComposeTestCheckFunc( testAccCheckDatabaseExists(resourceName, &db), resource.TestCheckResourceAttr(resourceName, "backup_retention_enabled", "true"), @@ -511,7 +511,7 @@ func TestAccLightsailDatabase_backupRetentionEnabled(t *testing.T) { }, }, { - Config: testAccDatabaseConfig_backupRetentionEnabled(rName, "false"), + Config: testAccDatabaseConfig_backupRetentionEnabled(rName, false), Check: resource.ComposeTestCheckFunc( testAccCheckDatabaseExists(resourceName, &db), resource.TestCheckResourceAttr(resourceName, "backup_retention_enabled", "false"), @@ -821,22 +821,13 @@ func testAccCheckDatabaseSnapshotDestroy(s *terraform.State) error { return nil } -func testAccDatabaseConfigBase() string { - return ` -data "aws_availability_zones" "available" { - state = "available" - - filter { - name = "opt-in-status" - values = ["opt-in-not-required"] - } -} -` +func testAccDatabaseConfig_base() string { + return acctest.ConfigAvailableAZsNoOptIn() } func testAccDatabaseConfig_basic(rName string) string { return acctest.ConfigCompose( - testAccDatabaseConfigBase(), + testAccDatabaseConfig_base(), fmt.Sprintf(` resource "aws_lightsail_database" "test" { relational_database_name = %[1]q @@ -853,7 +844,7 @@ resource "aws_lightsail_database" "test" { func testAccDatabaseConfig_masterDatabaseName(rName string, masterDatabaseName string) string { return acctest.ConfigCompose( - testAccDatabaseConfigBase(), + testAccDatabaseConfig_base(), fmt.Sprintf(` resource "aws_lightsail_database" "test" { relational_database_name = %[1]q @@ -870,7 +861,7 @@ resource "aws_lightsail_database" "test" { func testAccDatabaseConfig_masterUsername(rName string, masterUsername string) string { return acctest.ConfigCompose( - testAccDatabaseConfigBase(), + testAccDatabaseConfig_base(), fmt.Sprintf(` resource "aws_lightsail_database" "test" { relational_database_name = %[1]q @@ -887,7 +878,7 @@ resource "aws_lightsail_database" "test" { func testAccDatabaseConfig_masterPassword(rName string, masterPassword string) string { return acctest.ConfigCompose( - testAccDatabaseConfigBase(), + testAccDatabaseConfig_base(), fmt.Sprintf(` resource "aws_lightsail_database" "test" { relational_database_name = %[1]q @@ -904,7 +895,7 @@ resource "aws_lightsail_database" "test" { func testAccDatabaseConfig_preferredBackupWindow(rName string, preferredBackupWindow string) string { return acctest.ConfigCompose( - testAccDatabaseConfigBase(), + testAccDatabaseConfig_base(), fmt.Sprintf(` resource "aws_lightsail_database" "test" { relational_database_name = %[1]q @@ -923,7 +914,7 @@ resource "aws_lightsail_database" "test" { func testAccDatabaseConfig_preferredMaintenanceWindow(rName string, preferredMaintenanceWindow string) string { return acctest.ConfigCompose( - testAccDatabaseConfigBase(), + testAccDatabaseConfig_base(), fmt.Sprintf(` resource "aws_lightsail_database" "test" { relational_database_name = %[1]q @@ -940,9 +931,9 @@ resource "aws_lightsail_database" "test" { `, rName, preferredMaintenanceWindow)) } -func testAccDatabaseConfig_publiclyAccessible(rName string, publiclyAccessible string) string { +func testAccDatabaseConfig_publiclyAccessible(rName string, publiclyAccessible bool) string { return acctest.ConfigCompose( - testAccDatabaseConfigBase(), + testAccDatabaseConfig_base(), fmt.Sprintf(` resource "aws_lightsail_database" "test" { relational_database_name = %[1]q @@ -952,16 +943,16 @@ resource "aws_lightsail_database" "test" { master_username = "test" blueprint_id = "mysql_8_0" bundle_id = "micro_1_0" - publicly_accessible = %[2]q + publicly_accessible = %[2]t apply_immediately = true skip_final_snapshot = true } `, rName, publiclyAccessible)) } -func testAccDatabaseConfig_backupRetentionEnabled(rName string, backupRetentionEnabled string) string { +func testAccDatabaseConfig_backupRetentionEnabled(rName string, backupRetentionEnabled bool) string { return acctest.ConfigCompose( - testAccDatabaseConfigBase(), + testAccDatabaseConfig_base(), fmt.Sprintf(` resource "aws_lightsail_database" "test" { relational_database_name = %[1]q @@ -971,7 +962,7 @@ resource "aws_lightsail_database" "test" { master_username = "test" blueprint_id = "mysql_8_0" bundle_id = "micro_1_0" - backup_retention_enabled = %[2]q + backup_retention_enabled = %[2]t apply_immediately = true skip_final_snapshot = true } @@ -980,7 +971,7 @@ resource "aws_lightsail_database" "test" { func testAccDatabaseConfig_finalSnapshotName(rName string, sName string) string { return acctest.ConfigCompose( - testAccDatabaseConfigBase(), + testAccDatabaseConfig_base(), fmt.Sprintf(` resource "aws_lightsail_database" "test" { relational_database_name = %[1]q @@ -997,7 +988,7 @@ resource "aws_lightsail_database" "test" { func testAccDatabaseConfig_tags1(rName string, tagKey1, tagValue1 string) string { return acctest.ConfigCompose( - testAccDatabaseConfigBase(), + testAccDatabaseConfig_base(), fmt.Sprintf(` resource "aws_lightsail_database" "test" { relational_database_name = %[1]q @@ -1017,7 +1008,7 @@ resource "aws_lightsail_database" "test" { func testAccDatabaseConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return acctest.ConfigCompose( - testAccDatabaseConfigBase(), + testAccDatabaseConfig_base(), fmt.Sprintf(` resource "aws_lightsail_database" "test" { relational_database_name = %[1]q @@ -1038,7 +1029,7 @@ resource "aws_lightsail_database" "test" { func testAccDatabaseConfig_ha(rName string) string { return acctest.ConfigCompose( - testAccDatabaseConfigBase(), + testAccDatabaseConfig_base(), fmt.Sprintf(` resource "aws_lightsail_database" "test" { relational_database_name = %[1]q From 243b2f6b54701c2766dd58e0b061b6c453265407 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 3 Jan 2023 12:50:55 -0500 Subject: [PATCH 13/13] r/aws_lightsail_database: Add 'waitDatabasePubliclyAccessibleModified'. --- internal/service/lightsail/database.go | 6 ++++++ internal/service/lightsail/status.go | 26 ++++++++++++++++++++++++-- internal/service/lightsail/wait.go | 25 ++++++++++++++++++++++--- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/internal/service/lightsail/database.go b/internal/service/lightsail/database.go index f49054d3e9f8..5e7df959da6f 100644 --- a/internal/service/lightsail/database.go +++ b/internal/service/lightsail/database.go @@ -375,6 +375,12 @@ func resourceDatabaseUpdate(ctx context.Context, d *schema.ResourceData, meta in } } + if d.HasChange("publicly_accessible") { + if err := waitDatabasePubliclyAccessibleModified(ctx, conn, aws.String(d.Id()), d.Get("publicly_accessible").(bool)); err != nil { + return diag.Errorf("waiting for Lightsail Relational Database (%s) publicly accessible update: %s", d.Id(), err) + } + } + // Some Operations can complete before the Database enters the Available state. Added a waiter to make sure the Database is available before continuing. if _, err = waitDatabaseModified(ctx, conn, aws.String(d.Id())); err != nil { return diag.Errorf("waiting for Lightsail Relational Database (%s) to become available: %s", d.Id(), err) diff --git a/internal/service/lightsail/status.go b/internal/service/lightsail/status.go index 7d4ae66447d3..82d6c7ff0f59 100644 --- a/internal/service/lightsail/status.go +++ b/internal/service/lightsail/status.go @@ -114,8 +114,30 @@ func statusDatabaseBackupRetention(conn *lightsail.Lightsail, db *string) resour return nil, "Failed", fmt.Errorf("Error retrieving Database info for (%s)", dbValue) } - log.Printf("[DEBUG] Lightsail Database (%s) Backup Retention setting is currently %t", dbValue, *output.RelationalDatabase.BackupRetentionEnabled) - return output, strconv.FormatBool(*output.RelationalDatabase.BackupRetentionEnabled), nil + return output, strconv.FormatBool(aws.BoolValue(output.RelationalDatabase.BackupRetentionEnabled)), nil + } +} + +func statusDatabasePubliclyAccessible(conn *lightsail.Lightsail, db *string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + input := &lightsail.GetRelationalDatabaseInput{ + RelationalDatabaseName: db, + } + + dbValue := aws.StringValue(db) + log.Printf("[DEBUG] Checking if Lightsail Database (%s) Backup Retention setting has been updated.", dbValue) + + output, err := conn.GetRelationalDatabase(input) + + if err != nil { + return output, "FAILED", err + } + + if output.RelationalDatabase == nil { + return nil, "Failed", fmt.Errorf("Error retrieving Database info for (%s)", dbValue) + } + + return output, strconv.FormatBool(aws.BoolValue(output.RelationalDatabase.PubliclyAccessible)), nil } } diff --git a/internal/service/lightsail/wait.go b/internal/service/lightsail/wait.go index d13f4b5e9e0e..fb3c0d26e801 100644 --- a/internal/service/lightsail/wait.go +++ b/internal/service/lightsail/wait.go @@ -76,10 +76,10 @@ func waitDatabaseModified(ctx context.Context, conn *lightsail.Lightsail, db *st // waitDatabaseBackupRetentionModified waits for a Modified BackupRetention on Database return available -func waitDatabaseBackupRetentionModified(ctx context.Context, conn *lightsail.Lightsail, db *string, status *bool) error { +func waitDatabaseBackupRetentionModified(ctx context.Context, conn *lightsail.Lightsail, db *string, target bool) error { stateConf := &resource.StateChangeConf{ - Pending: []string{strconv.FormatBool(!aws.BoolValue(status))}, - Target: []string{strconv.FormatBool(aws.BoolValue(status))}, + Pending: []string{strconv.FormatBool(!target)}, + Target: []string{strconv.FormatBool(target)}, Refresh: statusDatabaseBackupRetention(conn, db), Timeout: DatabaseTimeout, Delay: DatabaseDelay, @@ -95,6 +95,25 @@ func waitDatabaseBackupRetentionModified(ctx context.Context, conn *lightsail.Li return err } +func waitDatabasePubliclyAccessibleModified(ctx context.Context, conn *lightsail.Lightsail, db *string, target bool) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{strconv.FormatBool(!target)}, + Target: []string{strconv.FormatBool(target)}, + Refresh: statusDatabasePubliclyAccessible(conn, db), + Timeout: DatabaseTimeout, + Delay: DatabaseDelay, + MinTimeout: DatabaseMinTimeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if _, ok := outputRaw.(*lightsail.GetRelationalDatabaseOutput); ok { + return err + } + + return err +} + func waitContainerServiceCreated(ctx context.Context, conn *lightsail.Lightsail, serviceName string, timeout time.Duration) error { stateConf := &resource.StateChangeConf{ Pending: []string{lightsail.ContainerServiceStatePending},