From 26862f2a2ae5d37bb682c55cbad5c307ce7f7da9 Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 23 Nov 2019 18:24:02 -0600 Subject: [PATCH 01/35] Added Lightsail load balancer resource, fixed 'disapear' typo in lightsail resources. --- aws/provider.go | 1 + aws/resource_aws_lightsail_domain_test.go | 2 +- aws/resource_aws_lightsail_instance_test.go | 2 +- aws/resource_aws_lightsail_load_balancer.go | 236 +++++++++++++ ...source_aws_lightsail_load_balancer_test.go | 316 ++++++++++++++++++ aws/resource_aws_lightsail_static_ip_test.go | 2 +- website/aws.erb | 3 + .../r/lightsail_load_balancer.html.markdown | 52 +++ 8 files changed, 611 insertions(+), 3 deletions(-) create mode 100644 aws/resource_aws_lightsail_load_balancer.go create mode 100644 aws/resource_aws_lightsail_load_balancer_test.go create mode 100644 website/docs/r/lightsail_load_balancer.html.markdown diff --git a/aws/provider.go b/aws/provider.go index 72c1e9e3bffa..c2e71419d29a 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -611,6 +611,7 @@ func Provider() terraform.ResourceProvider { "aws_lightsail_domain": resourceAwsLightsailDomain(), "aws_lightsail_instance": resourceAwsLightsailInstance(), "aws_lightsail_key_pair": resourceAwsLightsailKeyPair(), + "aws_lightsail_load_balancer": resourceAwsLightsailLoadBalancer(), "aws_lightsail_static_ip": resourceAwsLightsailStaticIp(), "aws_lightsail_static_ip_attachment": resourceAwsLightsailStaticIpAttachment(), "aws_lb_cookie_stickiness_policy": resourceAwsLBCookieStickinessPolicy(), diff --git a/aws/resource_aws_lightsail_domain_test.go b/aws/resource_aws_lightsail_domain_test.go index 2f2c1b033c97..1eef8d025ad5 100644 --- a/aws/resource_aws_lightsail_domain_test.go +++ b/aws/resource_aws_lightsail_domain_test.go @@ -44,7 +44,7 @@ func TestAccAWSLightsailDomain_disappears(t *testing.T) { }) if err != nil { - return fmt.Errorf("Error deleting Lightsail Domain in disapear test") + return fmt.Errorf("Error deleting Lightsail Domain in disappear test") } return nil diff --git a/aws/resource_aws_lightsail_instance_test.go b/aws/resource_aws_lightsail_instance_test.go index 5c4b9b687eb8..3a9f3107a82a 100644 --- a/aws/resource_aws_lightsail_instance_test.go +++ b/aws/resource_aws_lightsail_instance_test.go @@ -178,7 +178,7 @@ func TestAccAWSLightsailInstance_Tags(t *testing.T) { }) } -func TestAccAWSLightsailInstance_disapear(t *testing.T) { +func TestAccAWSLightsailInstance_disappear(t *testing.T) { var conf lightsail.Instance lightsailName := fmt.Sprintf("tf-test-lightsail-%d", acctest.RandInt()) diff --git a/aws/resource_aws_lightsail_load_balancer.go b/aws/resource_aws_lightsail_load_balancer.go new file mode 100644 index 000000000000..ea39410c5f62 --- /dev/null +++ b/aws/resource_aws_lightsail_load_balancer.go @@ -0,0 +1,236 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/lightsail" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" +) + +func resourceAwsLightsailLoadBalancer() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsLightsailLoadBalancerCreate, + Read: resourceAwsLightsailLoadBalancerRead, + Update: resourceAwsLightsailLoadBalancerUpdate, + Delete: resourceAwsLightsailLoadBalancerDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(2, 255), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z]`), "must begin with an alphabetic character"), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9_\-.]+[^._\-]$`), "must contain only alphanumeric characters, underscores, hyphens, and dots"), + ), + }, + "health_check_path": { + Type: schema.TypeString, + Optional: true, + Default: "/", + }, + "instance_port": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + ValidateFunc: validation.IntBetween(0, 65535), + }, + "tags": tagsSchema(), + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + }, + "dns_name": { + Type: schema.TypeString, + Computed: true, + }, + "protocol": { + Type: schema.TypeString, + Computed: true, + }, + "public_ports": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeInt}, + }, + }, + } +} + +func resourceAwsLightsailLoadBalancerCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).lightsailconn + + req := lightsail.CreateLoadBalancerInput{ + HealthCheckPath: aws.String(d.Get("health_check_path").(string)), + InstancePort: aws.Int64(int64(d.Get("instance_port").(int))), + LoadBalancerName: aws.String(d.Get("name").(string)), + } + + if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { + req.Tags = keyvaluetags.New(v).IgnoreAws().LightsailTags() + } + + resp, err := conn.CreateLoadBalancer(&req) + if err != nil { + return err + } + + if len(resp.Operations) == 0 { + return fmt.Errorf("No operations found for CreateInstance request") + } + + op := resp.Operations[0] + d.SetId(d.Get("name").(string)) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"Started"}, + Target: []string{"Completed", "Succeeded"}, + Refresh: resourceAwsLightsailLoadBalancerOperationRefreshFunc(op.Id, meta), + Timeout: 10 * time.Minute, + Delay: 5 * time.Second, + MinTimeout: 3 * time.Second, + } + + _, err = stateConf.WaitForState() + if err != nil { + // We don't return an error here because the Create call succeeded + log.Printf("[ERR] Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) + } + + return resourceAwsLightsailLoadBalancerRead(d, meta) +} + +func resourceAwsLightsailLoadBalancerRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).lightsailconn + resp, err := conn.GetLoadBalancer(&lightsail.GetLoadBalancerInput{ + LoadBalancerName: aws.String(d.Id()), + }) + + if err != nil { + if awsErr, ok := err.(awserr.Error); ok { + if awsErr.Code() == "NotFoundException" { + log.Printf("[WARN] Lightsail load balancer (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + return err + } + return err + } + + d.Set("arn", resp.LoadBalancer.Arn) + d.Set("created_at", resp.LoadBalancer.CreatedAt.Format(time.RFC3339)) + d.Set("health_check_path", resp.LoadBalancer.HealthCheckPath) + d.Set("instance_port", resp.LoadBalancer.InstancePort) + d.Set("name", resp.LoadBalancer.Name) + d.Set("protocol", resp.LoadBalancer.Protocol) + d.Set("public_ports", resp.LoadBalancer.PublicPorts) + + if err := d.Set("tags", keyvaluetags.LightsailKeyValueTags(resp.LoadBalancer.Tags).IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + return nil +} + +func resourceAwsLightsailLoadBalancerDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).lightsailconn + resp, err := conn.DeleteLoadBalancer(&lightsail.DeleteLoadBalancerInput{ + LoadBalancerName: aws.String(d.Id()), + }) + + op := resp.Operations[0] + + if err != nil { + return err + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"Started"}, + Target: []string{"Completed", "Succeeded"}, + Refresh: resourceAwsLightsailLoadBalancerOperationRefreshFunc(op.Id, meta), + Timeout: 10 * time.Minute, + Delay: 5 * time.Second, + MinTimeout: 3 * time.Second, + } + + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf( + "Error waiting for load balancer (%s) to become destroyed: %s", + d.Id(), err) + } + + return err +} + +func resourceAwsLightsailLoadBalancerUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).lightsailconn + + if d.HasChange("health_check_path") { + _, err := conn.UpdateLoadBalancerAttribute(&lightsail.UpdateLoadBalancerAttributeInput{ + AttributeName: aws.String("HealthCheckPath"), + AttributeValue: aws.String(d.Get("health_check_path").(string)), + LoadBalancerName: aws.String(d.Get("name").(string)), + }) + d.SetPartial("health_check_path") + if err != nil { + return err + } + } + + if d.HasChange("tags") { + o, n := d.GetChange("tags") + + if err := keyvaluetags.LightsailUpdateTags(conn, d.Id(), o, n); err != nil { + return fmt.Errorf("error updating Lightsail Instance (%s) tags: %s", d.Id(), err) + } + } + + return resourceAwsLightsailLoadBalancerRead(d, meta) +} + +// method to check the status of an Operation, which is returned from +// Create/Delete methods. +// Status's are an aws.OperationStatus enum: +// - NotStarted +// - Started +// - Failed +// - Completed +// - Succeeded (not documented?) +func resourceAwsLightsailLoadBalancerOperationRefreshFunc( + oid *string, meta interface{}) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + conn := meta.(*AWSClient).lightsailconn + log.Printf("[DEBUG] Checking if Lightsail Operation (%s) is Completed", *oid) + o, err := conn.GetOperation(&lightsail.GetOperationInput{ + OperationId: oid, + }) + if err != nil { + return o, "FAILED", err + } + + if o.Operation == nil { + return nil, "Failed", fmt.Errorf("Error retrieving Operation info for operation (%s)", *oid) + } + + log.Printf("[DEBUG] Lightsail Operation (%s) is currently %q", *oid, *o.Operation.Status) + return o, *o.Operation.Status, nil + } +} diff --git a/aws/resource_aws_lightsail_load_balancer_test.go b/aws/resource_aws_lightsail_load_balancer_test.go new file mode 100644 index 000000000000..f7e611296903 --- /dev/null +++ b/aws/resource_aws_lightsail_load_balancer_test.go @@ -0,0 +1,316 @@ +package aws + +import ( + "errors" + "fmt" + "log" + "regexp" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/lightsail" + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func init() { + resource.AddTestSweepers("aws_lightsail_load_balancer", &resource.Sweeper{ + Name: "aws_lightsail_load_balancer", + F: testSweepLightsailLoadBalancers, + }) +} + +func testSweepLightsailLoadBalancers(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("Error getting client: %s", err) + } + conn := client.(*AWSClient).lightsailconn + + input := &lightsail.GetLoadBalancersInput{} + var sweeperErrs *multierror.Error + + for { + output, err := conn.GetLoadBalancers(input) + + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping Lightsail Load Balancer sweep for %s: %s", region, err) + return nil + } + + if err != nil { + return fmt.Errorf("Error retrieving Lightsail Load Balancers: %s", err) + } + + for _, loadBalancer := range output.LoadBalancers { + name := aws.StringValue(loadBalancer.Name) + input := &lightsail.DeleteLoadBalancerInput{ + LoadBalancerName: loadBalancer.Name, + } + + log.Printf("[INFO] Deleting Lightsail Load Balancer: %s", name) + _, err := conn.DeleteLoadBalancer(input) + + if err != nil { + sweeperErr := fmt.Errorf("error deleting Lightsail Load Balancer (%s): %s", name, err) + log.Printf("[ERROR] %s", sweeperErr) + sweeperErrs = multierror.Append(sweeperErrs, sweeperErr) + } + } + + if aws.StringValue(output.NextPageToken) == "" { + break + } + + input.PageToken = output.NextPageToken + } + + return sweeperErrs.ErrorOrNil() +} + +func TestAccAWSLightsailLoadBalancer_basic(t *testing.T) { + var loadBalancer lightsail.LoadBalancer + lightsailLoadBalancerName := fmt.Sprintf("tf-test-lightsail-%d", acctest.RandInt()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSLightsail(t) }, + IDRefreshName: "aws_lightsail_load_balancer.lightsail_load_balancer_test", + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLightsailLoadBalancerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLightsailLoadBalancerConfig_basic(lightsailLoadBalancerName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLightsailLoadBalancerExists("aws_lightsail_load_balancer.lightsail_load_balancer_test", &loadBalancer), + resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "health_check_path"), + resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "instance_port"), + resource.TestCheckResourceAttr("aws_lightsail_load_balancer.lightsail_load_balancer_test", "tags.%", "0"), + ), + }, + }, + }) +} + +func TestAccAWSLightsailLoadBalancer_Name(t *testing.T) { + var conf lightsail.LoadBalancer + lightsailName := fmt.Sprintf("tf-test-lightsail-%d", acctest.RandInt()) + lightsailNameWithSpaces := fmt.Sprint(lightsailName, "string with spaces") + lightsailNameWithStartingDigit := fmt.Sprintf("01-%s", lightsailName) + lightsailNameWithUnderscore := fmt.Sprintf("%s_123456", lightsailName) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: "aws_lightsail_load_balancer.lightsail_load_balancer_test", + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLightsailLoadBalancerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLightsailLoadBalancerConfig_basic(lightsailNameWithSpaces), + ExpectError: regexp.MustCompile(`must contain only alphanumeric characters, underscores, hyphens, and dots`), + }, + { + Config: testAccAWSLightsailLoadBalancerConfig_basic(lightsailNameWithStartingDigit), + ExpectError: regexp.MustCompile(`must begin with an alphabetic character`), + }, + { + Config: testAccAWSLightsailLoadBalancerConfig_basic(lightsailName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLightsailLoadBalancerExists("aws_lightsail_load_balancer.lightsail_load_balancer_test", &conf), + resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "health_check_path"), + resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "instance_port"), + ), + }, + { + Config: testAccAWSLightsailLoadBalancerConfig_basic(lightsailNameWithUnderscore), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLightsailLoadBalancerExists("aws_lightsail_load_balancer.lightsail_load_balancer_test", &conf), + resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "health_check_path"), + resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "instance_port"), + ), + }, + }, + }) +} + +func TestAccAWSLightsailLoadBalancer_Tags(t *testing.T) { + var conf lightsail.LoadBalancer + lightsailLoadBalancerName := fmt.Sprintf("tf-test-lightsail-%d", acctest.RandInt()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSLightsail(t) }, + IDRefreshName: "aws_lightsail_load_balancer.lightsail_load_balancer_test", + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLightsailLoadBalancerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLightsailLoadBalancerConfig_tags1(lightsailLoadBalancerName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLightsailLoadBalancerExists("aws_lightsail_load_balancer.lightsail_load_balancer_test", &conf), + resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "health_check_path"), + resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "instance_port"), + resource.TestCheckResourceAttr("aws_lightsail_load_balancer.lightsail_load_balancer_test", "tags.%", "1"), + ), + }, + { + Config: testAccAWSLightsailLoadBalancerConfig_tags2(lightsailLoadBalancerName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLightsailLoadBalancerExists("aws_lightsail_load_balancer.lightsail_load_balancer_test", &conf), + resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "health_check_path"), + resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "instance_port"), + resource.TestCheckResourceAttr("aws_lightsail_load_balancer.lightsail_load_balancer_test", "tags.%", "2"), + ), + }, + }, + }) +} + +func testAccCheckAWSLightsailLoadBalancerExists(n string, res *lightsail.LoadBalancer) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No LightsailLoadBalancer ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).lightsailconn + + respLoadBalancer, err := conn.GetLoadBalancer(&lightsail.GetLoadBalancerInput{ + LoadBalancerName: aws.String(rs.Primary.Attributes["name"]), + }) + + if err != nil { + return err + } + + if respLoadBalancer == nil || respLoadBalancer.LoadBalancer == nil { + return fmt.Errorf("Load Balancer (%s) not found", rs.Primary.Attributes["name"]) + } + *res = *respLoadBalancer.LoadBalancer + return nil + } +} + +func TestAccAWSLightsailLoadBalancer_disappear(t *testing.T) { + var conf lightsail.LoadBalancer + lightsailLoadBalancerName := fmt.Sprintf("tf-test-lightsail-%d", acctest.RandInt()) + + testDestroy := func(*terraform.State) error { + // reach out and DELETE the Load Balancer + conn := testAccProvider.Meta().(*AWSClient).lightsailconn + _, err := conn.DeleteLoadBalancer(&lightsail.DeleteLoadBalancerInput{ + LoadBalancerName: aws.String(lightsailLoadBalancerName), + }) + + if err != nil { + return fmt.Errorf("error deleting Lightsail Load Balancer in disappear test") + } + + // sleep 7 seconds to give it time, so we don't have to poll + time.Sleep(7 * time.Second) + + return nil + } + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSLightsail(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLightsailLoadBalancerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLightsailLoadBalancerConfig_basic(lightsailLoadBalancerName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLightsailLoadBalancerExists("aws_lightsail_load_balancer.lightsail_load_balancer_test", &conf), + testDestroy, + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAWSLightsailLoadBalancerDestroy(s *terraform.State) error { + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_lightsail_load_balancer" { + continue + } + + conn := testAccProvider.Meta().(*AWSClient).lightsailconn + + resp, err := conn.GetLoadBalancer(&lightsail.GetLoadBalancerInput{ + LoadBalancerName: aws.String(rs.Primary.ID), + }) + + if err == nil { + if resp.LoadBalancer != nil { + return fmt.Errorf("Lightsail Load Balancer %q still exists", rs.Primary.ID) + } + } + + // Verify the error + if awsErr, ok := err.(awserr.Error); ok { + if awsErr.Code() == "NotFoundException" { + return nil + } + } + return err + } + + return nil +} + +func testAccAWSLightsailLoadBalancerConfig_basic(lightsailLoadBalancerName string) string { + return fmt.Sprintf(` +provider "aws" { + region = "us-east-1" +} + +resource "aws_lightsail_load_balancer" "lightsail_load_balancer_test" { + name = "%s" + health_check_path = "/" + instance_port = "80" +} +`, lightsailLoadBalancerName) +} + +func testAccAWSLightsailLoadBalancerConfig_tags1(lightsailLoadBalancerName string) string { + return fmt.Sprintf(` +provider "aws" { + region = "us-east-1" +} + +resource "aws_lightsail_load_balancer" "lightsail_load_balancer_test" { + name = "%s" + health_check_path = "/" + instance_port = "80" + tags = { + Name = "tf-test" + } +} +`, lightsailLoadBalancerName) +} + +func testAccAWSLightsailLoadBalancerConfig_tags2(lightsailLoadBalancerName string) string { + return fmt.Sprintf(` +provider "aws" { + region = "us-east-1" +} + +resource "aws_lightsail_load_balancer" "lightsail_load_balancer_test" { + name = "%s" + health_check_path = "/" + instance_port = "80" + tags = { + Name = "tf-test", + ExtraName = "tf-test" + } +} +`, lightsailLoadBalancerName) +} diff --git a/aws/resource_aws_lightsail_static_ip_test.go b/aws/resource_aws_lightsail_static_ip_test.go index 74ff6078f04e..7a29ac2cc332 100644 --- a/aws/resource_aws_lightsail_static_ip_test.go +++ b/aws/resource_aws_lightsail_static_ip_test.go @@ -96,7 +96,7 @@ func TestAccAWSLightsailStaticIp_disappears(t *testing.T) { }) if err != nil { - return fmt.Errorf("Error deleting Lightsail Static IP in disapear test") + return fmt.Errorf("Error deleting Lightsail Static IP in disappear test") } return nil diff --git a/website/aws.erb b/website/aws.erb index 8e36181d06d8..18cb225b3e41 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -1990,6 +1990,9 @@
  • aws_lightsail_key_pair
  • +
  • + aws_lightsail_load_balancer +
  • aws_lightsail_static_ip
  • diff --git a/website/docs/r/lightsail_load_balancer.html.markdown b/website/docs/r/lightsail_load_balancer.html.markdown new file mode 100644 index 000000000000..5f83eaa26973 --- /dev/null +++ b/website/docs/r/lightsail_load_balancer.html.markdown @@ -0,0 +1,52 @@ +--- +subcategory: "Lightsail" +layout: "aws" +page_title: "AWS: aws_lightsail_load_balancer" +description: |- + Provides a Lightsail Load Balancer +--- + +# Resource: aws_lightsail_load_balancer + +Creates a Lightsail load balancer resource. + +~> **Note:** Lightsail is currently only supported in a limited number of AWS Regions, please see ["Regions and Availability Zones in Amazon Lightsail"](https://lightsail.aws.amazon.com/ls/docs/overview/article/understanding-regions-and-availability-zones-in-amazon-lightsail) for more details + +## Example Usage, creating a new load balancer + +```hcl +resource "aws_lightsail_load_balancer" "load_balancer_test" { + name = "test-load-balancer" + health_check_path = "/" + instance_port = "80" + tags = { + foo = "bar" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the Lightsail load balancer. +* `instance_port` - (Required) The instance port the load balancer will connect. +* `health_check_path` - (Optional) The health check path of the load balancer. Default value "/". +* `tags` - (Optional) A mapping of tags to assign to the resource. + +## Attributes Reference + +The following attributes are exported in addition to the arguments listed above: + +* `arn` - The ARN of the Lightsail load balancer. +* `created_at` - The timestamp when the load balancer was created. +* `dns_name` - The DNS name of the load balancer. +* `id` - The name used for this load balancer. +* `protocol` - The protocol of the load balancer. +* `public_ports` - The public ports of the load balancer. + +Lightsail Load Balancers can be imported using their name, e.g. + +``` +$ terraform import aws_lightsail_load_balancer.website_load_balancer_ 'example-load-balancer' +``` From 3e88cf86819ff8eb64d15bb321386971a5fabe37 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 24 Feb 2021 16:23:12 -0500 Subject: [PATCH 02/35] Action Required: Removal of website/aws.erb File Reference: #14712 --- website/aws.erb | 3408 ----------------------------------------------- 1 file changed, 3408 deletions(-) delete mode 100644 website/aws.erb diff --git a/website/aws.erb b/website/aws.erb deleted file mode 100644 index 18cb225b3e41..000000000000 --- a/website/aws.erb +++ /dev/null @@ -1,3408 +0,0 @@ -<% wrap_layout :inner do %> - <% content_for :sidebar do %> - - <% end %> - <%= yield %> -<% end %> From 4fa980541791e38e7dbb75299dc5bf96b8c749f2 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung Date: Wed, 24 Feb 2021 16:40:27 -0500 Subject: [PATCH 03/35] Fixed: Action Required: Terraform Plugin SDK V2 Reference: #14551 --- aws/resource_aws_lightsail_load_balancer.go | 6 +++--- aws/resource_aws_lightsail_load_balancer_test.go | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_lightsail_load_balancer.go b/aws/resource_aws_lightsail_load_balancer.go index ea39410c5f62..668d986aa378 100644 --- a/aws/resource_aws_lightsail_load_balancer.go +++ b/aws/resource_aws_lightsail_load_balancer.go @@ -9,9 +9,9 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/lightsail" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) diff --git a/aws/resource_aws_lightsail_load_balancer_test.go b/aws/resource_aws_lightsail_load_balancer_test.go index f7e611296903..61377171d947 100644 --- a/aws/resource_aws_lightsail_load_balancer_test.go +++ b/aws/resource_aws_lightsail_load_balancer_test.go @@ -12,9 +12,9 @@ import ( "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/lightsail" "github.com/hashicorp/go-multierror" - "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) func init() { From 43bbaf4d61dcb58148720e97ffed678fda1717de Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Thu, 25 Feb 2021 08:11:52 -0500 Subject: [PATCH 04/35] Removed conflicting changes This Spelling error is already resolved in the main branch and this change is causing a conflict. --- aws/resource_aws_lightsail_domain_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_lightsail_domain_test.go b/aws/resource_aws_lightsail_domain_test.go index 1eef8d025ad5..2f2c1b033c97 100644 --- a/aws/resource_aws_lightsail_domain_test.go +++ b/aws/resource_aws_lightsail_domain_test.go @@ -44,7 +44,7 @@ func TestAccAWSLightsailDomain_disappears(t *testing.T) { }) if err != nil { - return fmt.Errorf("Error deleting Lightsail Domain in disappear test") + return fmt.Errorf("Error deleting Lightsail Domain in disapear test") } return nil From 7f65c4098fafd598f871d701b1a44846adac1f62 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung Date: Thu, 25 Feb 2021 10:15:44 -0500 Subject: [PATCH 05/35] * Fixed usage of SetPartial * Added dns_name to Read --- aws/resource_aws_lightsail_load_balancer.go | 3 ++- aws/resource_aws_lightsail_load_balancer_test.go | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_lightsail_load_balancer.go b/aws/resource_aws_lightsail_load_balancer.go index 668d986aa378..13a636b7497c 100644 --- a/aws/resource_aws_lightsail_load_balancer.go +++ b/aws/resource_aws_lightsail_load_balancer.go @@ -141,6 +141,7 @@ func resourceAwsLightsailLoadBalancerRead(d *schema.ResourceData, meta interface d.Set("name", resp.LoadBalancer.Name) d.Set("protocol", resp.LoadBalancer.Protocol) d.Set("public_ports", resp.LoadBalancer.PublicPorts) + d.Set("dns_name", resp.LoadBalancer.DnsName) if err := d.Set("tags", keyvaluetags.LightsailKeyValueTags(resp.LoadBalancer.Tags).IgnoreAws().Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) @@ -189,7 +190,7 @@ func resourceAwsLightsailLoadBalancerUpdate(d *schema.ResourceData, meta interfa AttributeValue: aws.String(d.Get("health_check_path").(string)), LoadBalancerName: aws.String(d.Get("name").(string)), }) - d.SetPartial("health_check_path") + d.Set("health_check_path", d.Get("health_check_path").(string)) if err != nil { return err } diff --git a/aws/resource_aws_lightsail_load_balancer_test.go b/aws/resource_aws_lightsail_load_balancer_test.go index 61377171d947..052b45d7d952 100644 --- a/aws/resource_aws_lightsail_load_balancer_test.go +++ b/aws/resource_aws_lightsail_load_balancer_test.go @@ -88,6 +88,7 @@ func TestAccAWSLightsailLoadBalancer_basic(t *testing.T) { testAccCheckAWSLightsailLoadBalancerExists("aws_lightsail_load_balancer.lightsail_load_balancer_test", &loadBalancer), resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "health_check_path"), resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "instance_port"), + resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "dns_name"), resource.TestCheckResourceAttr("aws_lightsail_load_balancer.lightsail_load_balancer_test", "tags.%", "0"), ), }, @@ -271,7 +272,6 @@ func testAccAWSLightsailLoadBalancerConfig_basic(lightsailLoadBalancerName strin provider "aws" { region = "us-east-1" } - resource "aws_lightsail_load_balancer" "lightsail_load_balancer_test" { name = "%s" health_check_path = "/" @@ -285,7 +285,6 @@ func testAccAWSLightsailLoadBalancerConfig_tags1(lightsailLoadBalancerName strin provider "aws" { region = "us-east-1" } - resource "aws_lightsail_load_balancer" "lightsail_load_balancer_test" { name = "%s" health_check_path = "/" @@ -302,7 +301,6 @@ func testAccAWSLightsailLoadBalancerConfig_tags2(lightsailLoadBalancerName strin provider "aws" { region = "us-east-1" } - resource "aws_lightsail_load_balancer" "lightsail_load_balancer_test" { name = "%s" health_check_path = "/" From 9e4d71b2566a5a38da0d0da6cf6d825da19d3615 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung Date: Fri, 26 Feb 2021 13:40:04 -0500 Subject: [PATCH 06/35] Fixed: * terrafmt issue * Removed provider from tests * added missing semgrp.yml config file --- .semgrep.yml | 188 ++++++++++++++++++ ...source_aws_lightsail_load_balancer_test.go | 29 +-- .../r/lightsail_load_balancer.html.markdown | 6 +- 3 files changed, 201 insertions(+), 22 deletions(-) create mode 100644 .semgrep.yml diff --git a/.semgrep.yml b/.semgrep.yml new file mode 100644 index 000000000000..cc6d638df505 --- /dev/null +++ b/.semgrep.yml @@ -0,0 +1,188 @@ +rules: + - id: acceptance-test-naming-parent-disappears + languages: [go] + message: Prefer naming acceptance tests with _disappears_Parent suffix + paths: + include: + - 'aws/*_test.go' + patterns: + - pattern: func $FUNCNAME(t *testing.T) { ... } + - metavariable-regex: + metavariable: "$FUNCNAME" + regex: "^TestAcc[^_]+_([a-zA-Z]+[dD]isappears|[^_]+_disappears)$" + severity: WARNING + + - id: aws-sdk-go-multiple-service-imports + languages: [go] + message: Resources should not implement multiple AWS service functionality + paths: + exclude: + - aws/config.go + - aws/structure.go + - aws/validators.go + - aws/*wafregional*.go + - aws/resource_aws_serverlessapplicationrepository_cloudformation_stack.go + - aws/*_test.go + - aws/internal/keyvaluetags/ + - aws/internal/service/wafregional/ + # Legacy resource handling + - aws/resource_aws_autoscaling_group.go + - aws/resource_aws_efs_mount_target.go + - aws/resource_aws_elastic_beanstalk_environment.go + - aws/resource_aws_elb.go + - aws/resource_aws_iam_server_certificate.go + - aws/resource_aws_lambda_event_source_mapping.go + - aws/resource_aws_launch_configuration.go + - aws/resource_aws_lb.go + - aws/resource_aws_s3_bucket_object.go + include: + - aws/ + patterns: + - pattern: | + import ("$X") + import ("$Y") + - metavariable-regex: + metavariable: '$X' + regex: '^"github.com/aws/aws-sdk-go/service/[^/]+"$' + - metavariable-regex: + metavariable: '$Y' + regex: '^"github.com/aws/aws-sdk-go/service/[^/]+"$' + severity: WARNING + + - id: prefer-aws-go-sdk-pointer-conversion-assignment + languages: [go] + message: Prefer AWS Go SDK pointer conversion functions for dereferencing during assignment, e.g. aws.StringValue() + paths: + exclude: + - aws/cloudfront_distribution_configuration_structure.go + - aws/data_source_aws_route_table.go + - aws/opsworks_layers.go + - aws/resource* + - aws/structure.go + - aws/waf_helpers.go + - aws/internal/generators/ + - aws/internal/keyvaluetags/ + - awsproviderlint/vendor/ + include: + - aws/ + patterns: + - pattern: '$LHS = *$RHS' + - pattern-not: '*$LHS2 = *$RHS' + severity: WARNING + + - id: aws-go-sdk-pointer-conversion-ResourceData-SetId + fix: d.SetId(aws.StringValue($VALUE)) + languages: [go] + message: Prefer AWS Go SDK pointer conversion aws.StringValue() function for dereferencing during d.SetId() + paths: + include: + - aws/ + pattern: 'd.SetId(*$VALUE)' + severity: WARNING + + - id: helper-schema-Set-extraneous-NewSet-with-flattenStringList + languages: [go] + message: Prefer `flattenStringSet()` function for casting a list of string pointers to a set + paths: + include: + - aws/ + patterns: + - pattern: schema.NewSet(schema.HashString, flattenStringList($APIOBJECT)) + - pattern-not-inside: func flattenStringSet(list []*string) *schema.Set { ... } + severity: WARNING + + - id: helper-schema-Set-extraneous-expandStringList-with-List + languages: [go] + message: Prefer `expandStringSet()` function for casting a set to a list of string pointers + paths: + include: + - aws/ + patterns: + - pattern-either: + - pattern: expandStringList($SET.List()) + - pattern: | + $LIST := $SET.List() + ... + expandStringList($LIST) + - pattern-not-inside: func expandStringSet(configured *schema.Set) []*string { ... } + severity: WARNING + + + - id: helper-schema-ResourceData-GetOk-with-extraneous-conditional + languages: [go] + message: Zero value conditional check after `d.GetOk()` is extraneous + paths: + include: + - aws/ + patterns: + - pattern-either: + - pattern: if $VALUE, $OK := d.GetOk($KEY); $OK && $VALUE.(bool) { $BODY } + - pattern: if $VALUE, $OK := d.GetOk($KEY); $OK && $VALUE.(int) != 0 { $BODY } + - pattern: if $VALUE, $OK := d.GetOk($KEY); $OK && $VALUE.(int) > 0 { $BODY } + - pattern: if $VALUE, $OK := d.GetOk($KEY); $OK && $VALUE.(string) != "" { $BODY } + - pattern: if $VALUE, $OK := d.GetOk($KEY); $OK && len($VALUE.(string)) > 0 { $BODY } + severity: WARNING + + - id: helper-schema-resource-Retry-without-TimeoutError-check + languages: [go] + message: Check resource.Retry() errors with tfresource.TimedOut() + paths: + exclude: + - "*_test.go" + include: + - aws/ + patterns: + - pattern-either: + - pattern: | + $ERR := resource.Retry(...) + ... + return ... + - pattern: | + $ERR = resource.Retry(...) + ... + return ... + - pattern-not: | + $ERR := resource.Retry(...) + ... + if isResourceTimeoutError($ERR) { ... } + ... + return ... + - pattern-not: | + $ERR = resource.Retry(...) + ... + if isResourceTimeoutError($ERR) { ... } + ... + return ... + - pattern-not: | + $ERR := resource.Retry(...) + ... + if tfresource.TimedOut($ERR) { ... } + ... + return ... + - pattern-not: | + $ERR = resource.Retry(...) + ... + if tfresource.TimedOut($ERR) { ... } + ... + return ... + severity: WARNING + + - id: is-not-found-error + languages: [go] + message: Check for resource.NotFoundError errors with tfresource.NotFound() + paths: + include: + - aws/ + patterns: + - pattern-either: + - patterns: + - pattern: | + var $CAST *resource.NotFoundError + ... + errors.As($ERR, &$CAST) + - pattern-not-inside: func NotFound(err error) bool { ... } + - patterns: + - pattern: | + $X, $Y := $ERR.(*resource.NotFoundError) + - pattern-not-inside: func isResourceNotFoundError(err error) bool { ... } + severity: WARNING \ No newline at end of file diff --git a/aws/resource_aws_lightsail_load_balancer_test.go b/aws/resource_aws_lightsail_load_balancer_test.go index 052b45d7d952..32fdc2b2214d 100644 --- a/aws/resource_aws_lightsail_load_balancer_test.go +++ b/aws/resource_aws_lightsail_load_balancer_test.go @@ -269,26 +269,20 @@ func testAccCheckAWSLightsailLoadBalancerDestroy(s *terraform.State) error { func testAccAWSLightsailLoadBalancerConfig_basic(lightsailLoadBalancerName string) string { return fmt.Sprintf(` -provider "aws" { - region = "us-east-1" -} resource "aws_lightsail_load_balancer" "lightsail_load_balancer_test" { - name = "%s" - health_check_path = "/" - instance_port = "80" + name = "%s" + health_check_path = "/" + instance_port = "80" } `, lightsailLoadBalancerName) } func testAccAWSLightsailLoadBalancerConfig_tags1(lightsailLoadBalancerName string) string { return fmt.Sprintf(` -provider "aws" { - region = "us-east-1" -} resource "aws_lightsail_load_balancer" "lightsail_load_balancer_test" { - name = "%s" - health_check_path = "/" - instance_port = "80" + name = "%s" + health_check_path = "/" + instance_port = "80" tags = { Name = "tf-test" } @@ -298,15 +292,12 @@ resource "aws_lightsail_load_balancer" "lightsail_load_balancer_test" { func testAccAWSLightsailLoadBalancerConfig_tags2(lightsailLoadBalancerName string) string { return fmt.Sprintf(` -provider "aws" { - region = "us-east-1" -} resource "aws_lightsail_load_balancer" "lightsail_load_balancer_test" { - name = "%s" - health_check_path = "/" - instance_port = "80" + name = "%s" + health_check_path = "/" + instance_port = "80" tags = { - Name = "tf-test", + Name = "tf-test" ExtraName = "tf-test" } } diff --git a/website/docs/r/lightsail_load_balancer.html.markdown b/website/docs/r/lightsail_load_balancer.html.markdown index 5f83eaa26973..8a49945cee8d 100644 --- a/website/docs/r/lightsail_load_balancer.html.markdown +++ b/website/docs/r/lightsail_load_balancer.html.markdown @@ -16,9 +16,9 @@ Creates a Lightsail load balancer resource. ```hcl resource "aws_lightsail_load_balancer" "load_balancer_test" { - name = "test-load-balancer" - health_check_path = "/" - instance_port = "80" + name = "test-load-balancer" + health_check_path = "/" + instance_port = "80" tags = { foo = "bar" } From 7c24c548da8554862c60783801ad948be31dc46f Mon Sep 17 00:00:00 2001 From: Brittan DeYoung Date: Fri, 26 Feb 2021 14:55:45 -0500 Subject: [PATCH 07/35] fixed: AWSR002 --- aws/resource_aws_lightsail_load_balancer.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_lightsail_load_balancer.go b/aws/resource_aws_lightsail_load_balancer.go index 13a636b7497c..eb7b46ac921a 100644 --- a/aws/resource_aws_lightsail_load_balancer.go +++ b/aws/resource_aws_lightsail_load_balancer.go @@ -118,6 +118,8 @@ func resourceAwsLightsailLoadBalancerCreate(d *schema.ResourceData, meta interfa func resourceAwsLightsailLoadBalancerRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).lightsailconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + resp, err := conn.GetLoadBalancer(&lightsail.GetLoadBalancerInput{ LoadBalancerName: aws.String(d.Id()), }) @@ -143,7 +145,7 @@ func resourceAwsLightsailLoadBalancerRead(d *schema.ResourceData, meta interface d.Set("public_ports", resp.LoadBalancer.PublicPorts) d.Set("dns_name", resp.LoadBalancer.DnsName) - if err := d.Set("tags", keyvaluetags.LightsailKeyValueTags(resp.LoadBalancer.Tags).IgnoreAws().Map()); err != nil { + if err := d.Set("tags", keyvaluetags.LightsailKeyValueTags(resp.LoadBalancer.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } From a2c4807f3fe62fcfb7863f309ccb950384b93a64 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung Date: Tue, 2 Mar 2021 10:45:51 -0500 Subject: [PATCH 08/35] Created Internal Waiter files --- .../service/lightsail/waiter/status.go | 32 ++++++++ .../service/lightsail/waiter/waiter.go | 48 +++++++++++ aws/resource_aws_lightsail_load_balancer.go | 81 ++++--------------- ...source_aws_lightsail_load_balancer_test.go | 64 ++++++++------- 4 files changed, 131 insertions(+), 94 deletions(-) create mode 100644 aws/internal/service/lightsail/waiter/status.go create mode 100644 aws/internal/service/lightsail/waiter/waiter.go diff --git a/aws/internal/service/lightsail/waiter/status.go b/aws/internal/service/lightsail/waiter/status.go new file mode 100644 index 000000000000..a31c50e5d70d --- /dev/null +++ b/aws/internal/service/lightsail/waiter/status.go @@ -0,0 +1,32 @@ +package waiter + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/service/lightsail" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +// LightsailOperationStatus is a method to check the status of a Lightsail Operation +func LightsailOperationStatus(conn *lightsail.Lightsail, oid string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + input := &lightsail.GetOperationInput{ + OperationId: oid, + } + log.Printf("[DEBUG] Checking if Lightsail Operation (%s) is Completed", &oid) + + output, err := conn.GetOperation(input) + + if err != nil { + return output, "FAILED", err + } + + if output.Operation == nil { + return nil, "Failed", fmt.Errorf("Error retrieving Operation info for operation (%s)", &oid) + } + + log.Printf("[DEBUG] Lightsail Operation (%s) is currently %q", &oid, *output.Operation.Status) + return output, *output.Operation.Status, nil + } +} diff --git a/aws/internal/service/lightsail/waiter/waiter.go b/aws/internal/service/lightsail/waiter/waiter.go new file mode 100644 index 000000000000..467eeb88acbd --- /dev/null +++ b/aws/internal/service/lightsail/waiter/waiter.go @@ -0,0 +1,48 @@ +package waiter + +import ( + "time" + + "github.com/aws/aws-sdk-go/service/lightsail" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const ( + // OperationStatusNotStarted is a OperationStatus enum value + OperationStatusNotStarted = "NotStarted" + // OperationStatusStarted is a OperationStatus enum value + OperationStatusStarted = "Started" + // OperationStatusFailed is a OperationStatus enum value + OperationStatusFailed = "Failed" + // OperationStatusCompleted is a OperationStatus enum value + OperationStatusCompleted = "Completed" + // OperationStatusSucceeded is a OperationStatus enum value + OperationStatusSucceeded = "Succeeded" + + // OperationTimeout is the Timout Value for Operations + OperationTimeout = 10 * time.Minute + // OperationDelay is the Delay Value for Operations + OperationDelay = 5 * time.Second + // OperationMinTimeout is the MinTimout Value for Operations + OperationMinTimeout = 3 * time.Second +) + +// OperationCreated waits for an Operation to return Succeeded or Compleated +func OperationCreated(conn *lightsail.Lightsail, oid string) (*lightsail.GetOperationOutput, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{OperationStatusStarted}, + Target: []string{OperationStatusCompleted, OperationStatusSucceeded}, + Refresh: LightsailOperationStatus(conn, oid), + Timeout: OperationTimeout, + Delay: OperationDelay, + MinTimeout: OperationMinTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*glue.GetOperationOutput); ok { + return output, err + } + + return nil, err +} diff --git a/aws/resource_aws_lightsail_load_balancer.go b/aws/resource_aws_lightsail_load_balancer.go index eb7b46ac921a..7f58594d840b 100644 --- a/aws/resource_aws_lightsail_load_balancer.go +++ b/aws/resource_aws_lightsail_load_balancer.go @@ -6,10 +6,11 @@ import ( "regexp" "time" + "./aws/internal/service/lightsail/waiter" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/lightsail" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" @@ -98,19 +99,9 @@ func resourceAwsLightsailLoadBalancerCreate(d *schema.ResourceData, meta interfa op := resp.Operations[0] d.SetId(d.Get("name").(string)) - stateConf := &resource.StateChangeConf{ - Pending: []string{"Started"}, - Target: []string{"Completed", "Succeeded"}, - Refresh: resourceAwsLightsailLoadBalancerOperationRefreshFunc(op.Id, meta), - Timeout: 10 * time.Minute, - Delay: 5 * time.Second, - MinTimeout: 3 * time.Second, - } - - _, err = stateConf.WaitForState() + _, err = waiter.OperationCreated(conn, op.Id) if err != nil { - // We don't return an error here because the Create call succeeded - log.Printf("[ERR] Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) + return fmt.Errorf("Error waiting for load balancer (%s) to become ready: %s", d.Id(), err) } return resourceAwsLightsailLoadBalancerRead(d, meta) @@ -124,6 +115,8 @@ func resourceAwsLightsailLoadBalancerRead(d *schema.ResourceData, meta interface LoadBalancerName: aws.String(d.Id()), }) + lb := resp.LoadBalancer + if err != nil { if awsErr, ok := err.(awserr.Error); ok { if awsErr.Code() == "NotFoundException" { @@ -136,16 +129,16 @@ func resourceAwsLightsailLoadBalancerRead(d *schema.ResourceData, meta interface return err } - d.Set("arn", resp.LoadBalancer.Arn) - d.Set("created_at", resp.LoadBalancer.CreatedAt.Format(time.RFC3339)) - d.Set("health_check_path", resp.LoadBalancer.HealthCheckPath) - d.Set("instance_port", resp.LoadBalancer.InstancePort) - d.Set("name", resp.LoadBalancer.Name) - d.Set("protocol", resp.LoadBalancer.Protocol) - d.Set("public_ports", resp.LoadBalancer.PublicPorts) - d.Set("dns_name", resp.LoadBalancer.DnsName) + d.Set("arn", lb.Arn) + d.Set("created_at", lb.CreatedAt.Format(time.RFC3339)) + d.Set("health_check_path", lb.HealthCheckPath) + d.Set("instance_port", lb.InstancePort) + d.Set("name", lb.Name) + d.Set("protocol", lb.Protocol) + d.Set("public_ports", lb.PublicPorts) + d.Set("dns_name", lb.DnsName) - if err := d.Set("tags", keyvaluetags.LightsailKeyValueTags(resp.LoadBalancer.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + if err := d.Set("tags", keyvaluetags.LightsailKeyValueTags(lb.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } @@ -164,20 +157,9 @@ func resourceAwsLightsailLoadBalancerDelete(d *schema.ResourceData, meta interfa return err } - stateConf := &resource.StateChangeConf{ - Pending: []string{"Started"}, - Target: []string{"Completed", "Succeeded"}, - Refresh: resourceAwsLightsailLoadBalancerOperationRefreshFunc(op.Id, meta), - Timeout: 10 * time.Minute, - Delay: 5 * time.Second, - MinTimeout: 3 * time.Second, - } - - _, err = stateConf.WaitForState() + _, err = waiter.OperationCreated(conn, op.Id) if err != nil { - return fmt.Errorf( - "Error waiting for load balancer (%s) to become destroyed: %s", - d.Id(), err) + return fmt.Errorf("Error waiting for load balancer (%s) to become destroyed: %s", d.Id(), err) } return err @@ -208,32 +190,3 @@ func resourceAwsLightsailLoadBalancerUpdate(d *schema.ResourceData, meta interfa return resourceAwsLightsailLoadBalancerRead(d, meta) } - -// method to check the status of an Operation, which is returned from -// Create/Delete methods. -// Status's are an aws.OperationStatus enum: -// - NotStarted -// - Started -// - Failed -// - Completed -// - Succeeded (not documented?) -func resourceAwsLightsailLoadBalancerOperationRefreshFunc( - oid *string, meta interface{}) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - conn := meta.(*AWSClient).lightsailconn - log.Printf("[DEBUG] Checking if Lightsail Operation (%s) is Completed", *oid) - o, err := conn.GetOperation(&lightsail.GetOperationInput{ - OperationId: oid, - }) - if err != nil { - return o, "FAILED", err - } - - if o.Operation == nil { - return nil, "Failed", fmt.Errorf("Error retrieving Operation info for operation (%s)", *oid) - } - - log.Printf("[DEBUG] Lightsail Operation (%s) is currently %q", *oid, *o.Operation.Status) - return o, *o.Operation.Status, nil - } -} diff --git a/aws/resource_aws_lightsail_load_balancer_test.go b/aws/resource_aws_lightsail_load_balancer_test.go index 32fdc2b2214d..07e3ec9df0df 100644 --- a/aws/resource_aws_lightsail_load_balancer_test.go +++ b/aws/resource_aws_lightsail_load_balancer_test.go @@ -74,22 +74,23 @@ func testSweepLightsailLoadBalancers(region string) error { func TestAccAWSLightsailLoadBalancer_basic(t *testing.T) { var loadBalancer lightsail.LoadBalancer - lightsailLoadBalancerName := fmt.Sprintf("tf-test-lightsail-%d", acctest.RandInt()) + lightsailLoadBalancerName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lightsail_load_balancer.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSLightsail(t) }, - IDRefreshName: "aws_lightsail_load_balancer.lightsail_load_balancer_test", + IDRefreshName: resourceName, Providers: testAccProviders, CheckDestroy: testAccCheckAWSLightsailLoadBalancerDestroy, Steps: []resource.TestStep{ { Config: testAccAWSLightsailLoadBalancerConfig_basic(lightsailLoadBalancerName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSLightsailLoadBalancerExists("aws_lightsail_load_balancer.lightsail_load_balancer_test", &loadBalancer), - resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "health_check_path"), - resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "instance_port"), - resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "dns_name"), - resource.TestCheckResourceAttr("aws_lightsail_load_balancer.lightsail_load_balancer_test", "tags.%", "0"), + testAccCheckAWSLightsailLoadBalancerExists(resourceName, &loadBalancer), + resource.TestCheckResourceAttrSet(resourceName, "health_check_path"), + resource.TestCheckResourceAttrSet(resourceName, "instance_port"), + resource.TestCheckResourceAttrSet(resourceName, "dns_name"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, }, @@ -98,14 +99,15 @@ func TestAccAWSLightsailLoadBalancer_basic(t *testing.T) { func TestAccAWSLightsailLoadBalancer_Name(t *testing.T) { var conf lightsail.LoadBalancer - lightsailName := fmt.Sprintf("tf-test-lightsail-%d", acctest.RandInt()) + lightsailName := acctest.RandomWithPrefix("tf-acc-test") lightsailNameWithSpaces := fmt.Sprint(lightsailName, "string with spaces") lightsailNameWithStartingDigit := fmt.Sprintf("01-%s", lightsailName) lightsailNameWithUnderscore := fmt.Sprintf("%s_123456", lightsailName) + resourceName := "aws_lightsail_load_balancer.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, - IDRefreshName: "aws_lightsail_load_balancer.lightsail_load_balancer_test", + IDRefreshName: resourceName, Providers: testAccProviders, CheckDestroy: testAccCheckAWSLightsailLoadBalancerDestroy, Steps: []resource.TestStep{ @@ -120,17 +122,17 @@ func TestAccAWSLightsailLoadBalancer_Name(t *testing.T) { { Config: testAccAWSLightsailLoadBalancerConfig_basic(lightsailName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSLightsailLoadBalancerExists("aws_lightsail_load_balancer.lightsail_load_balancer_test", &conf), - resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "health_check_path"), - resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "instance_port"), + testAccCheckAWSLightsailLoadBalancerExists(resourceName, &conf), + resource.TestCheckResourceAttrSet(resourceName, "health_check_path"), + resource.TestCheckResourceAttrSet(resourceName, "instance_port"), ), }, { Config: testAccAWSLightsailLoadBalancerConfig_basic(lightsailNameWithUnderscore), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSLightsailLoadBalancerExists("aws_lightsail_load_balancer.lightsail_load_balancer_test", &conf), - resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "health_check_path"), - resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "instance_port"), + testAccCheckAWSLightsailLoadBalancerExists(resourceName, &conf), + resource.TestCheckResourceAttrSet(resourceName, "health_check_path"), + resource.TestCheckResourceAttrSet(resourceName, "instance_port"), ), }, }, @@ -139,30 +141,31 @@ func TestAccAWSLightsailLoadBalancer_Name(t *testing.T) { func TestAccAWSLightsailLoadBalancer_Tags(t *testing.T) { var conf lightsail.LoadBalancer - lightsailLoadBalancerName := fmt.Sprintf("tf-test-lightsail-%d", acctest.RandInt()) + lightsailLoadBalancerName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lightsail_load_balancer.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSLightsail(t) }, - IDRefreshName: "aws_lightsail_load_balancer.lightsail_load_balancer_test", + IDRefreshName: resourceName, Providers: testAccProviders, CheckDestroy: testAccCheckAWSLightsailLoadBalancerDestroy, Steps: []resource.TestStep{ { Config: testAccAWSLightsailLoadBalancerConfig_tags1(lightsailLoadBalancerName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSLightsailLoadBalancerExists("aws_lightsail_load_balancer.lightsail_load_balancer_test", &conf), - resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "health_check_path"), - resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "instance_port"), - resource.TestCheckResourceAttr("aws_lightsail_load_balancer.lightsail_load_balancer_test", "tags.%", "1"), + testAccCheckAWSLightsailLoadBalancerExists(resourceName, &conf), + resource.TestCheckResourceAttrSet(resourceName, "health_check_path"), + resource.TestCheckResourceAttrSet(resourceName, "instance_port"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), ), }, { Config: testAccAWSLightsailLoadBalancerConfig_tags2(lightsailLoadBalancerName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSLightsailLoadBalancerExists("aws_lightsail_load_balancer.lightsail_load_balancer_test", &conf), - resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "health_check_path"), - resource.TestCheckResourceAttrSet("aws_lightsail_load_balancer.lightsail_load_balancer_test", "instance_port"), - resource.TestCheckResourceAttr("aws_lightsail_load_balancer.lightsail_load_balancer_test", "tags.%", "2"), + testAccCheckAWSLightsailLoadBalancerExists(resourceName, &conf), + resource.TestCheckResourceAttrSet(resourceName, "health_check_path"), + resource.TestCheckResourceAttrSet(resourceName, "instance_port"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), ), }, }, @@ -200,7 +203,8 @@ func testAccCheckAWSLightsailLoadBalancerExists(n string, res *lightsail.LoadBal func TestAccAWSLightsailLoadBalancer_disappear(t *testing.T) { var conf lightsail.LoadBalancer - lightsailLoadBalancerName := fmt.Sprintf("tf-test-lightsail-%d", acctest.RandInt()) + lightsailLoadBalancerName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lightsail_load_balancer.test" testDestroy := func(*terraform.State) error { // reach out and DELETE the Load Balancer @@ -227,7 +231,7 @@ func TestAccAWSLightsailLoadBalancer_disappear(t *testing.T) { { Config: testAccAWSLightsailLoadBalancerConfig_basic(lightsailLoadBalancerName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSLightsailLoadBalancerExists("aws_lightsail_load_balancer.lightsail_load_balancer_test", &conf), + testAccCheckAWSLightsailLoadBalancerExists(resourceName, &conf), testDestroy, ), ExpectNonEmptyPlan: true, @@ -269,7 +273,7 @@ func testAccCheckAWSLightsailLoadBalancerDestroy(s *terraform.State) error { func testAccAWSLightsailLoadBalancerConfig_basic(lightsailLoadBalancerName string) string { return fmt.Sprintf(` -resource "aws_lightsail_load_balancer" "lightsail_load_balancer_test" { +resource "aws_lightsail_load_balancer" "test" { name = "%s" health_check_path = "/" instance_port = "80" @@ -279,7 +283,7 @@ resource "aws_lightsail_load_balancer" "lightsail_load_balancer_test" { func testAccAWSLightsailLoadBalancerConfig_tags1(lightsailLoadBalancerName string) string { return fmt.Sprintf(` -resource "aws_lightsail_load_balancer" "lightsail_load_balancer_test" { +resource "aws_lightsail_load_balancer" "test" { name = "%s" health_check_path = "/" instance_port = "80" @@ -292,7 +296,7 @@ resource "aws_lightsail_load_balancer" "lightsail_load_balancer_test" { func testAccAWSLightsailLoadBalancerConfig_tags2(lightsailLoadBalancerName string) string { return fmt.Sprintf(` -resource "aws_lightsail_load_balancer" "lightsail_load_balancer_test" { +resource "aws_lightsail_load_balancer" "test" { name = "%s" health_check_path = "/" instance_port = "80" From 6a146ba316a57d195685425c370c232b3e6fc700 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung Date: Tue, 2 Mar 2021 10:50:46 -0500 Subject: [PATCH 09/35] FIxed: * old reference to glue * string reference oid * waiter import --- aws/internal/service/lightsail/waiter/status.go | 2 +- aws/internal/service/lightsail/waiter/waiter.go | 2 +- aws/resource_aws_lightsail_load_balancer.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/aws/internal/service/lightsail/waiter/status.go b/aws/internal/service/lightsail/waiter/status.go index a31c50e5d70d..9acac3d115d3 100644 --- a/aws/internal/service/lightsail/waiter/status.go +++ b/aws/internal/service/lightsail/waiter/status.go @@ -12,7 +12,7 @@ import ( func LightsailOperationStatus(conn *lightsail.Lightsail, oid string) resource.StateRefreshFunc { return func() (interface{}, string, error) { input := &lightsail.GetOperationInput{ - OperationId: oid, + OperationId: aws.String(oid), } log.Printf("[DEBUG] Checking if Lightsail Operation (%s) is Completed", &oid) diff --git a/aws/internal/service/lightsail/waiter/waiter.go b/aws/internal/service/lightsail/waiter/waiter.go index 467eeb88acbd..bb51f3a96c46 100644 --- a/aws/internal/service/lightsail/waiter/waiter.go +++ b/aws/internal/service/lightsail/waiter/waiter.go @@ -40,7 +40,7 @@ func OperationCreated(conn *lightsail.Lightsail, oid string) (*lightsail.GetOper outputRaw, err := stateConf.WaitForState() - if output, ok := outputRaw.(*glue.GetOperationOutput); ok { + if output, ok := outputRaw.(*lightsail.GetOperationOutput); ok { return output, err } diff --git a/aws/resource_aws_lightsail_load_balancer.go b/aws/resource_aws_lightsail_load_balancer.go index 7f58594d840b..d981e8e62650 100644 --- a/aws/resource_aws_lightsail_load_balancer.go +++ b/aws/resource_aws_lightsail_load_balancer.go @@ -6,7 +6,7 @@ import ( "regexp" "time" - "./aws/internal/service/lightsail/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lightsail/waiter" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" From df2e0e340e3a83b4ea8becefd68d78108b5e10d2 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung Date: Tue, 2 Mar 2021 10:52:01 -0500 Subject: [PATCH 10/35] added aws sdk import --- aws/internal/service/lightsail/waiter/status.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/internal/service/lightsail/waiter/status.go b/aws/internal/service/lightsail/waiter/status.go index 9acac3d115d3..70a28bdd6f28 100644 --- a/aws/internal/service/lightsail/waiter/status.go +++ b/aws/internal/service/lightsail/waiter/status.go @@ -4,6 +4,7 @@ import ( "fmt" "log" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/lightsail" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) From 26ae51426849d85f432ee9e36888e604ca955b68 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung Date: Tue, 2 Mar 2021 13:59:32 -0500 Subject: [PATCH 11/35] Fixed: Waiter input type Feature: Path acctests added --- .../service/lightsail/waiter/status.go | 5 +- .../service/lightsail/waiter/waiter.go | 2 +- ...source_aws_lightsail_load_balancer_test.go | 175 +++++++++++------- 3 files changed, 111 insertions(+), 71 deletions(-) diff --git a/aws/internal/service/lightsail/waiter/status.go b/aws/internal/service/lightsail/waiter/status.go index 70a28bdd6f28..a072135a6fe5 100644 --- a/aws/internal/service/lightsail/waiter/status.go +++ b/aws/internal/service/lightsail/waiter/status.go @@ -4,16 +4,15 @@ import ( "fmt" "log" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/lightsail" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) // LightsailOperationStatus is a method to check the status of a Lightsail Operation -func LightsailOperationStatus(conn *lightsail.Lightsail, oid string) resource.StateRefreshFunc { +func LightsailOperationStatus(conn *lightsail.Lightsail, oid *string) resource.StateRefreshFunc { return func() (interface{}, string, error) { input := &lightsail.GetOperationInput{ - OperationId: aws.String(oid), + OperationId: oid, } log.Printf("[DEBUG] Checking if Lightsail Operation (%s) is Completed", &oid) diff --git a/aws/internal/service/lightsail/waiter/waiter.go b/aws/internal/service/lightsail/waiter/waiter.go index bb51f3a96c46..a8737f25355b 100644 --- a/aws/internal/service/lightsail/waiter/waiter.go +++ b/aws/internal/service/lightsail/waiter/waiter.go @@ -28,7 +28,7 @@ const ( ) // OperationCreated waits for an Operation to return Succeeded or Compleated -func OperationCreated(conn *lightsail.Lightsail, oid string) (*lightsail.GetOperationOutput, error) { +func OperationCreated(conn *lightsail.Lightsail, oid *string) (*lightsail.GetOperationOutput, error) { stateConf := &resource.StateChangeConf{ Pending: []string{OperationStatusStarted}, Target: []string{OperationStatusCompleted, OperationStatusSucceeded}, diff --git a/aws/resource_aws_lightsail_load_balancer_test.go b/aws/resource_aws_lightsail_load_balancer_test.go index 07e3ec9df0df..8947b3dcc531 100644 --- a/aws/resource_aws_lightsail_load_balancer_test.go +++ b/aws/resource_aws_lightsail_load_balancer_test.go @@ -6,7 +6,6 @@ import ( "log" "regexp" "testing" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" @@ -73,8 +72,8 @@ func testSweepLightsailLoadBalancers(region string) error { } func TestAccAWSLightsailLoadBalancer_basic(t *testing.T) { - var loadBalancer lightsail.LoadBalancer - lightsailLoadBalancerName := acctest.RandomWithPrefix("tf-acc-test") + var lb lightsail.LoadBalancer + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_lightsail_load_balancer.test" resource.ParallelTest(t, resource.TestCase{ @@ -84,25 +83,29 @@ func TestAccAWSLightsailLoadBalancer_basic(t *testing.T) { CheckDestroy: testAccCheckAWSLightsailLoadBalancerDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLightsailLoadBalancerConfig_basic(lightsailLoadBalancerName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSLightsailLoadBalancerExists(resourceName, &loadBalancer), - resource.TestCheckResourceAttrSet(resourceName, "health_check_path"), - resource.TestCheckResourceAttrSet(resourceName, "instance_port"), + Config: testAccAWSLightsailLoadBalancerConfigBasic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLightsailLoadBalancerExists(resourceName, &lb), + resource.TestCheckResourceAttr(resourceName, "health_check_path", "/"), + resource.TestCheckResourceAttr(resourceName, "instance_port", "80"), resource.TestCheckResourceAttrSet(resourceName, "dns_name"), - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } func TestAccAWSLightsailLoadBalancer_Name(t *testing.T) { - var conf lightsail.LoadBalancer - lightsailName := acctest.RandomWithPrefix("tf-acc-test") - lightsailNameWithSpaces := fmt.Sprint(lightsailName, "string with spaces") - lightsailNameWithStartingDigit := fmt.Sprintf("01-%s", lightsailName) - lightsailNameWithUnderscore := fmt.Sprintf("%s_123456", lightsailName) + var lb lightsail.LoadBalancer + rName := acctest.RandomWithPrefix("tf-acc-test") + lightsailNameWithSpaces := fmt.Sprint(rName, "string with spaces") + lightsailNameWithStartingDigit := fmt.Sprintf("01-%s", rName) + lightsailNameWithUnderscore := fmt.Sprintf("%s_123456", rName) resourceName := "aws_lightsail_load_balancer.test" resource.ParallelTest(t, resource.TestCase{ @@ -112,25 +115,25 @@ func TestAccAWSLightsailLoadBalancer_Name(t *testing.T) { CheckDestroy: testAccCheckAWSLightsailLoadBalancerDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLightsailLoadBalancerConfig_basic(lightsailNameWithSpaces), + Config: testAccAWSLightsailLoadBalancerConfigBasic(lightsailNameWithSpaces), ExpectError: regexp.MustCompile(`must contain only alphanumeric characters, underscores, hyphens, and dots`), }, { - Config: testAccAWSLightsailLoadBalancerConfig_basic(lightsailNameWithStartingDigit), + Config: testAccAWSLightsailLoadBalancerConfigBasic(lightsailNameWithStartingDigit), ExpectError: regexp.MustCompile(`must begin with an alphabetic character`), }, { - Config: testAccAWSLightsailLoadBalancerConfig_basic(lightsailName), + Config: testAccAWSLightsailLoadBalancerConfigBasic(rName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSLightsailLoadBalancerExists(resourceName, &conf), + testAccCheckAWSLightsailLoadBalancerExists(resourceName, &lb), resource.TestCheckResourceAttrSet(resourceName, "health_check_path"), resource.TestCheckResourceAttrSet(resourceName, "instance_port"), ), }, { - Config: testAccAWSLightsailLoadBalancerConfig_basic(lightsailNameWithUnderscore), + Config: testAccAWSLightsailLoadBalancerConfigBasic(lightsailNameWithUnderscore), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSLightsailLoadBalancerExists(resourceName, &conf), + testAccCheckAWSLightsailLoadBalancerExists(resourceName, &lb), resource.TestCheckResourceAttrSet(resourceName, "health_check_path"), resource.TestCheckResourceAttrSet(resourceName, "instance_port"), ), @@ -139,9 +142,42 @@ func TestAccAWSLightsailLoadBalancer_Name(t *testing.T) { }) } +func TestAccAWSLightsailLoadBalancer_Path(t *testing.T) { + var lb lightsail.LoadBalancer + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lightsail_load_balancer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSLightsail(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLightsailLoadBalancerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLightsailLoadBalancerConfigPath(rName, "/"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLightsailLoadBalancerExists(resourceName, &lb), + resource.TestCheckResourceAttr(resourceName, "health_check_path", "/"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSLightsailLoadBalancerConfigPath(rName, "/healthcheck"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLightsailLoadBalancerExists(resourceName, &lb), + resource.TestCheckResourceAttr(resourceName, "health_check_path", "/healthcheck"), + ), + }, + }, + }) +} + func TestAccAWSLightsailLoadBalancer_Tags(t *testing.T) { - var conf lightsail.LoadBalancer - lightsailLoadBalancerName := acctest.RandomWithPrefix("tf-acc-test") + var lb1, lb2, lb3 lightsail.LoadBalancer + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_lightsail_load_balancer.test" resource.ParallelTest(t, resource.TestCase{ @@ -151,21 +187,33 @@ func TestAccAWSLightsailLoadBalancer_Tags(t *testing.T) { CheckDestroy: testAccCheckAWSLightsailLoadBalancerDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLightsailLoadBalancerConfig_tags1(lightsailLoadBalancerName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSLightsailLoadBalancerExists(resourceName, &conf), - resource.TestCheckResourceAttrSet(resourceName, "health_check_path"), - resource.TestCheckResourceAttrSet(resourceName, "instance_port"), + Config: testAccAWSLightsailLoadBalancerConfigTags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLightsailLoadBalancerExists(resourceName, &lb1), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), }, { - Config: testAccAWSLightsailLoadBalancerConfig_tags2(lightsailLoadBalancerName), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSLightsailLoadBalancerExists(resourceName, &conf), - resource.TestCheckResourceAttrSet(resourceName, "health_check_path"), - resource.TestCheckResourceAttrSet(resourceName, "instance_port"), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSLightsailLoadBalancerConfigTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLightsailLoadBalancerExists(resourceName, &lb2), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSLightsailLoadBalancerConfigTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLightsailLoadBalancerExists(resourceName, &lb3), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, }, @@ -201,38 +249,21 @@ func testAccCheckAWSLightsailLoadBalancerExists(n string, res *lightsail.LoadBal } } -func TestAccAWSLightsailLoadBalancer_disappear(t *testing.T) { - var conf lightsail.LoadBalancer - lightsailLoadBalancerName := acctest.RandomWithPrefix("tf-acc-test") +func TestAccAWSLightsailLoadBalancer_disappears(t *testing.T) { + var lb lightsail.LoadBalancer + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_lightsail_load_balancer.test" - testDestroy := func(*terraform.State) error { - // reach out and DELETE the Load Balancer - conn := testAccProvider.Meta().(*AWSClient).lightsailconn - _, err := conn.DeleteLoadBalancer(&lightsail.DeleteLoadBalancerInput{ - LoadBalancerName: aws.String(lightsailLoadBalancerName), - }) - - if err != nil { - return fmt.Errorf("error deleting Lightsail Load Balancer in disappear test") - } - - // sleep 7 seconds to give it time, so we don't have to poll - time.Sleep(7 * time.Second) - - return nil - } - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSLightsail(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSLightsailLoadBalancerDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLightsailLoadBalancerConfig_basic(lightsailLoadBalancerName), + Config: testAccAWSLightsailLoadBalancerConfigBasic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSLightsailLoadBalancerExists(resourceName, &conf), - testDestroy, + testAccCheckAWSLightsailLoadBalancerExists(resourceName, &lb), + testAccCheckResourceDisappears(testAccProvider, resourceAwsLightsailLoadBalancer(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -271,39 +302,49 @@ func testAccCheckAWSLightsailLoadBalancerDestroy(s *terraform.State) error { return nil } -func testAccAWSLightsailLoadBalancerConfig_basic(lightsailLoadBalancerName string) string { +func testAccAWSLightsailLoadBalancerConfigBasic(rName string) string { return fmt.Sprintf(` resource "aws_lightsail_load_balancer" "test" { - name = "%s" + name = %[1]q health_check_path = "/" instance_port = "80" } -`, lightsailLoadBalancerName) +`, rName) +} + +func testAccAWSLightsailLoadBalancerConfigPath(rName string, rPath string) string { + return fmt.Sprintf(` +resource "aws_lightsail_load_balancer" "test" { + name = %[1]q + health_check_path = %[2]q + instance_port = "80" +} +`, rName, rPath) } -func testAccAWSLightsailLoadBalancerConfig_tags1(lightsailLoadBalancerName string) string { +func testAccAWSLightsailLoadBalancerConfigTags1(rName string, tagKey1, tagValue1 string) string { return fmt.Sprintf(` resource "aws_lightsail_load_balancer" "test" { - name = "%s" + name = %[1]q health_check_path = "/" instance_port = "80" tags = { - Name = "tf-test" + %[2]q = %[3]q } } -`, lightsailLoadBalancerName) +`, rName, tagKey1, tagValue1) } -func testAccAWSLightsailLoadBalancerConfig_tags2(lightsailLoadBalancerName string) string { +func testAccAWSLightsailLoadBalancerConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` resource "aws_lightsail_load_balancer" "test" { - name = "%s" + name = %[1]q health_check_path = "/" instance_port = "80" tags = { - Name = "tf-test" - ExtraName = "tf-test" + %[2]q = %[3]q + %[4]q = %[5]q } } -`, lightsailLoadBalancerName) +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) } From d9beabdd3fbcc2604573d095606e800ac709c37a Mon Sep 17 00:00:00 2001 From: Brittan DeYoung Date: Tue, 2 Mar 2021 14:15:09 -0500 Subject: [PATCH 12/35] Updated healthcheckpath test name --- aws/resource_aws_lightsail_load_balancer_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_lightsail_load_balancer_test.go b/aws/resource_aws_lightsail_load_balancer_test.go index 8947b3dcc531..deab8830fa9a 100644 --- a/aws/resource_aws_lightsail_load_balancer_test.go +++ b/aws/resource_aws_lightsail_load_balancer_test.go @@ -142,7 +142,7 @@ func TestAccAWSLightsailLoadBalancer_Name(t *testing.T) { }) } -func TestAccAWSLightsailLoadBalancer_Path(t *testing.T) { +func TestAccAWSLightsailLoadBalancer_HealthCheckPath(t *testing.T) { var lb lightsail.LoadBalancer rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_lightsail_load_balancer.test" @@ -153,7 +153,7 @@ func TestAccAWSLightsailLoadBalancer_Path(t *testing.T) { CheckDestroy: testAccCheckAWSLightsailLoadBalancerDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSLightsailLoadBalancerConfigPath(rName, "/"), + Config: testAccAWSLightsailLoadBalancerConfigHealthCheckPath(rName, "/"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLightsailLoadBalancerExists(resourceName, &lb), resource.TestCheckResourceAttr(resourceName, "health_check_path", "/"), @@ -165,7 +165,7 @@ func TestAccAWSLightsailLoadBalancer_Path(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAWSLightsailLoadBalancerConfigPath(rName, "/healthcheck"), + Config: testAccAWSLightsailLoadBalancerConfigHealthCheckPath(rName, "/healthcheck"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLightsailLoadBalancerExists(resourceName, &lb), resource.TestCheckResourceAttr(resourceName, "health_check_path", "/healthcheck"), @@ -312,7 +312,7 @@ resource "aws_lightsail_load_balancer" "test" { `, rName) } -func testAccAWSLightsailLoadBalancerConfigPath(rName string, rPath string) string { +func testAccAWSLightsailLoadBalancerConfigHealthCheckPath(rName string, rPath string) string { return fmt.Sprintf(` resource "aws_lightsail_load_balancer" "test" { name = %[1]q From be02e54585d3652a5dd9fe4633b1c41916a529ba Mon Sep 17 00:00:00 2001 From: Brittan DeYoung Date: Tue, 2 Mar 2021 14:51:44 -0500 Subject: [PATCH 13/35] fixed import order an String format --- aws/internal/service/lightsail/waiter/status.go | 8 +++++--- aws/resource_aws_lightsail_load_balancer.go | 3 +-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/aws/internal/service/lightsail/waiter/status.go b/aws/internal/service/lightsail/waiter/status.go index a072135a6fe5..49aabe6625dc 100644 --- a/aws/internal/service/lightsail/waiter/status.go +++ b/aws/internal/service/lightsail/waiter/status.go @@ -14,7 +14,9 @@ func LightsailOperationStatus(conn *lightsail.Lightsail, oid *string) resource.S input := &lightsail.GetOperationInput{ OperationId: oid, } - log.Printf("[DEBUG] Checking if Lightsail Operation (%s) is Completed", &oid) + + oidValue := *oid + log.Printf("[DEBUG] Checking if Lightsail Operation (%s) is Completed", oidValue) output, err := conn.GetOperation(input) @@ -23,10 +25,10 @@ func LightsailOperationStatus(conn *lightsail.Lightsail, oid *string) resource.S } if output.Operation == nil { - return nil, "Failed", fmt.Errorf("Error retrieving Operation info for operation (%s)", &oid) + return nil, "Failed", fmt.Errorf("Error retrieving Operation info for operation (%s)", oidValue) } - log.Printf("[DEBUG] Lightsail Operation (%s) is currently %q", &oid, *output.Operation.Status) + log.Printf("[DEBUG] Lightsail Operation (%s) is currently %q", oidValue, *output.Operation.Status) return output, *output.Operation.Status, nil } } diff --git a/aws/resource_aws_lightsail_load_balancer.go b/aws/resource_aws_lightsail_load_balancer.go index d981e8e62650..935bdbd7549d 100644 --- a/aws/resource_aws_lightsail_load_balancer.go +++ b/aws/resource_aws_lightsail_load_balancer.go @@ -6,14 +6,13 @@ import ( "regexp" "time" - "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lightsail/waiter" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/lightsail" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/lightsail/waiter" ) func resourceAwsLightsailLoadBalancer() *schema.Resource { From 72ad6568975a0240b6f393ec1e4d59c40b958226 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung Date: Tue, 2 Mar 2021 14:54:59 -0500 Subject: [PATCH 14/35] switched to aws.stringvalue --- aws/internal/service/lightsail/waiter/status.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/aws/internal/service/lightsail/waiter/status.go b/aws/internal/service/lightsail/waiter/status.go index 49aabe6625dc..2fc3d562da9f 100644 --- a/aws/internal/service/lightsail/waiter/status.go +++ b/aws/internal/service/lightsail/waiter/status.go @@ -4,6 +4,8 @@ import ( "fmt" "log" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/lightsail" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -15,7 +17,7 @@ func LightsailOperationStatus(conn *lightsail.Lightsail, oid *string) resource.S OperationId: oid, } - oidValue := *oid + oidValue := aws.StringValue(oid) log.Printf("[DEBUG] Checking if Lightsail Operation (%s) is Completed", oidValue) output, err := conn.GetOperation(input) From cb72b94102d1d959438c6259eead34f95ee89bff Mon Sep 17 00:00:00 2001 From: Brittan DeYoung Date: Tue, 2 Mar 2021 15:03:31 -0500 Subject: [PATCH 15/35] resolved import order --- aws/internal/service/lightsail/waiter/status.go | 1 - 1 file changed, 1 deletion(-) diff --git a/aws/internal/service/lightsail/waiter/status.go b/aws/internal/service/lightsail/waiter/status.go index 2fc3d562da9f..1be4377c7f34 100644 --- a/aws/internal/service/lightsail/waiter/status.go +++ b/aws/internal/service/lightsail/waiter/status.go @@ -5,7 +5,6 @@ import ( "log" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/lightsail" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) From acffe679eaf8e1a81914e69f9257847de3a34009 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 11:44:09 -0400 Subject: [PATCH 16/35] lightsail: Amend consts add ResLoadBalancer --- internal/service/lightsail/consts.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/service/lightsail/consts.go b/internal/service/lightsail/consts.go index 73a9a19fe6ae..a381e6042b98 100644 --- a/internal/service/lightsail/consts.go +++ b/internal/service/lightsail/consts.go @@ -1,8 +1,9 @@ package lightsail const ( - ResCertificate = "Certificate" - ResDatabase = "Database" - ResTags = "Tags" - ResDomainEntry = "Domain Entry" + ResCertificate = "Certificate" + ResDatabase = "Database" + ResTags = "Tags" + ResDomainEntry = "Domain Entry" + ResLoadBalancer = "Load Balancer" ) From 841e27b0addb17754d935a20eeaac63b87b85e7c Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 11:44:27 -0400 Subject: [PATCH 17/35] lightsail: Amend find add FindLoadBalancerByName --- internal/service/lightsail/find.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/internal/service/lightsail/find.go b/internal/service/lightsail/find.go index 5851492a4c17..3fd994f36edc 100644 --- a/internal/service/lightsail/find.go +++ b/internal/service/lightsail/find.go @@ -156,3 +156,29 @@ func FindDomainEntryById(ctx context.Context, conn *lightsail.Lightsail, id stri return entry, nil } + +func FindLoadBalancerByName(ctx context.Context, conn *lightsail.Lightsail, name string) (*lightsail.LoadBalancer, error) { + + in := &lightsail.GetLoadBalancerInput{LoadBalancerName: aws.String(name)} + out, err := conn.GetLoadBalancerWithContext(ctx, in) + + if tfawserr.ErrCodeEquals(err, lightsail.ErrCodeNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: in, + } + } + + if err != nil { + return nil, err + } + + if out == nil || out.LoadBalancer == nil { + return nil, tfresource.NewEmptyResultError(in) + } + + lb := out.LoadBalancer + + return lb, nil + +} From d2157fd0fc9a7faf5005a7250ae36c54312d0dc0 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 11:44:43 -0400 Subject: [PATCH 18/35] lightsail: Add lb resource --- internal/service/lightsail/lb.go | 247 +++++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 internal/service/lightsail/lb.go diff --git a/internal/service/lightsail/lb.go b/internal/service/lightsail/lb.go new file mode 100644 index 000000000000..be47cff76ec6 --- /dev/null +++ b/internal/service/lightsail/lb.go @@ -0,0 +1,247 @@ +package lightsail + +import ( + "context" + "errors" + "regexp" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/lightsail" + "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" + "github.com/hashicorp/terraform-provider-aws/internal/create" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/internal/verify" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func ResourceLoadBalancer() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: resourceLoadBalancerCreate, + ReadWithoutTimeout: resourceLoadBalancerRead, + UpdateWithoutTimeout: resourceLoadBalancerUpdate, + DeleteWithoutTimeout: resourceLoadBalancerDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + }, + "dns_name": { + Type: schema.TypeString, + Computed: true, + }, + "health_check_path": { + Type: schema.TypeString, + Optional: true, + Default: "/", + }, + "instance_port": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + ValidateFunc: validation.IntBetween(0, 65535), + }, + "ip_address_type": { + Type: schema.TypeString, + Optional: true, + Default: "dualstack", + ValidateFunc: validation.StringInSlice([]string{ + "dualstack", + "ipv4", + }, false), + }, + "protocol": { + Type: schema.TypeString, + Computed: true, + }, + "public_ports": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeInt}, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(2, 255), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z]`), "must begin with an alphabetic character"), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9_\-.]+[^._\-]$`), "must contain only alphanumeric characters, underscores, hyphens, and dots"), + ), + }, + "support_code": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tftags.TagsSchema(), + "tags_all": tftags.TagsSchemaComputed(), + }, + CustomizeDiff: verify.SetTagsDiff, + } +} + +func resourceLoadBalancerCreate(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{}))) + + in := lightsail.CreateLoadBalancerInput{ + HealthCheckPath: aws.String(d.Get("health_check_path").(string)), + InstancePort: aws.Int64(int64(d.Get("instance_port").(int))), + LoadBalancerName: aws.String(d.Get("name").(string)), + } + + if len(tags) > 0 { + in.Tags = Tags(tags.IgnoreAWS()) + } + + out, err := conn.CreateLoadBalancer(&in) + + if err != nil { + return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), err) + } + + if len(out.Operations) == 0 { + return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), errors.New("No operations found for Create Load Balancer request")) + } + + op := out.Operations[0] + d.SetId(d.Get("name").(string)) + + err = waitOperation(conn, op.Id) + if err != nil { + return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), errors.New("Error waiting for Create Load Balancer request operation")) + } + + return resourceLoadBalancerRead(ctx, d, meta) +} + +func resourceLoadBalancerRead(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 + + lb, err := FindLoadBalancerByName(ctx, conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + create.LogNotFoundRemoveState(names.Lightsail, create.ErrActionReading, ResLoadBalancer, d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return create.DiagError(names.Lightsail, create.ErrActionReading, ResLoadBalancer, d.Id(), err) + } + + d.Set("arn", lb.Arn) + d.Set("created_at", lb.CreatedAt.Format(time.RFC3339)) + d.Set("dns_name", lb.DnsName) + d.Set("health_check_path", lb.HealthCheckPath) + d.Set("instance_port", lb.InstancePort) + d.Set("ip_address_type", lb.IpAddressType) + d.Set("protocol", lb.Protocol) + d.Set("public_ports", lb.PublicPorts) + d.Set("name", lb.Name) + d.Set("support_code", lb.SupportCode) + + tags := KeyValueTags(lb.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig) + + //lintignore:AWSR002 + if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { + return create.DiagError(names.Lightsail, create.ErrActionReading, ResLoadBalancer, d.Id(), err) + } + + if err := d.Set("tags_all", tags.Map()); err != nil { + return create.DiagError(names.Lightsail, create.ErrActionReading, ResLoadBalancer, d.Id(), err) + } + + return nil +} + +func resourceLoadBalancerUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).LightsailConn + + in := &lightsail.UpdateLoadBalancerAttributeInput{ + LoadBalancerName: aws.String(d.Get("name").(string)), + } + + if d.HasChange("health_check_path") { + healthCheckIn := in + healthCheckIn.AttributeName = aws.String("HealthCheckPath") + healthCheckIn.AttributeValue = aws.String(d.Get("health_check_path").(string)) + + out, err := conn.UpdateLoadBalancerAttributeWithContext(ctx, healthCheckIn) + + if err != nil { + return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), err) + } + + if len(out.Operations) == 0 { + return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), errors.New("No operations found for Create Load Balancer request")) + } + + op := out.Operations[0] + d.SetId(d.Get("name").(string)) + + err = waitOperation(conn, op.Id) + if err != nil { + return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), errors.New("Error waiting for Create Load Balancer request operation")) + } + } + + if d.HasChange("tags") { + o, n := d.GetChange("tags") + + if err := UpdateTags(conn, d.Id(), o, n); err != nil { + return create.DiagError(names.Lightsail, create.ErrActionUpdating, ResLoadBalancer, 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 create.DiagError(names.Lightsail, create.ErrActionUpdating, ResLoadBalancer, d.Id(), err) + } + } + + return resourceLoadBalancerRead(ctx, d, meta) +} + +func resourceLoadBalancerDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).LightsailConn + out, err := conn.DeleteLoadBalancer(&lightsail.DeleteLoadBalancerInput{ + LoadBalancerName: aws.String(d.Id()), + }) + + if err != nil { + return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), err) + } + + if len(out.Operations) == 0 { + return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), errors.New("No operations found for Create Load Balancer request")) + } + + op := out.Operations[0] + d.SetId(d.Get("name").(string)) + + err = waitOperation(conn, op.Id) + if err != nil { + return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), errors.New("Error waiting for Create Load Balancer request operation")) + } + + return nil +} From 57a637d0bfd416cbceb944674c7f194aef9aeace Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 12:00:41 -0400 Subject: [PATCH 19/35] provider: Amend provider to add aws_lightsail_lb --- internal/provider/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/provider/provider.go b/internal/provider/provider.go index b3605acc0f9b..18dc5f465096 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -1715,6 +1715,7 @@ func New(_ context.Context) (*schema.Provider, error) { "aws_lightsail_instance": lightsail.ResourceInstance(), "aws_lightsail_instance_public_ports": lightsail.ResourceInstancePublicPorts(), "aws_lightsail_key_pair": lightsail.ResourceKeyPair(), + "aws_lightsail_lb": lightsail.ResourceLoadBalancer(), "aws_lightsail_static_ip": lightsail.ResourceStaticIP(), "aws_lightsail_static_ip_attachment": lightsail.ResourceStaticIPAttachment(), From cd77a7d3b251028f5866d94b6d26fc3031355239 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 12:06:02 -0400 Subject: [PATCH 20/35] lightsail: Add aws_lightsail_lb_test * Add acceptance tests for `aws_lightsail_lb` resource. --- internal/service/lightsail/lb_test.go | 331 ++++++++++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 internal/service/lightsail/lb_test.go diff --git a/internal/service/lightsail/lb_test.go b/internal/service/lightsail/lb_test.go new file mode 100644 index 000000000000..d229635af81a --- /dev/null +++ b/internal/service/lightsail/lb_test.go @@ -0,0 +1,331 @@ +package lightsail_test + +import ( + "context" + "errors" + "fmt" + "regexp" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/lightsail" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/create" + tflightsail "github.com/hashicorp/terraform-provider-aws/internal/service/lightsail" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccLightsailLoadBalancer_basic(t *testing.T) { + var lb lightsail.LoadBalancer + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_lightsail_lb.test" + + 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: testAccCheckLoadBalancerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLoadBalancerConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoadBalancerExists(resourceName, &lb), + resource.TestCheckResourceAttr(resourceName, "health_check_path", "/"), + resource.TestCheckResourceAttr(resourceName, "instance_port", "80"), + resource.TestCheckResourceAttrSet(resourceName, "dns_name"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccLightsailLoadBalancer_Name(t *testing.T) { + var lb lightsail.LoadBalancer + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + lightsailNameWithSpaces := fmt.Sprint(rName, "string with spaces") + lightsailNameWithStartingDigit := fmt.Sprintf("01-%s", rName) + lightsailNameWithUnderscore := fmt.Sprintf("%s_123456", rName) + resourceName := "aws_lightsail_lb.test" + + 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: testAccCheckLoadBalancerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLoadBalancerConfig_basic(lightsailNameWithSpaces), + ExpectError: regexp.MustCompile(`must contain only alphanumeric characters, underscores, hyphens, and dots`), + }, + { + Config: testAccLoadBalancerConfig_basic(lightsailNameWithStartingDigit), + ExpectError: regexp.MustCompile(`must begin with an alphabetic character`), + }, + { + Config: testAccLoadBalancerConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckLoadBalancerExists(resourceName, &lb), + resource.TestCheckResourceAttrSet(resourceName, "health_check_path"), + resource.TestCheckResourceAttrSet(resourceName, "instance_port"), + ), + }, + { + Config: testAccLoadBalancerConfig_basic(lightsailNameWithUnderscore), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckLoadBalancerExists(resourceName, &lb), + resource.TestCheckResourceAttrSet(resourceName, "health_check_path"), + resource.TestCheckResourceAttrSet(resourceName, "instance_port"), + ), + }, + }, + }) +} + +func TestAccLightsailLoadBalancer_HealthCheckPath(t *testing.T) { + var lb lightsail.LoadBalancer + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_lightsail_lb.test" + + 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, + Steps: []resource.TestStep{ + { + Config: testAccLoadBalancerConfig_healthCheckPath(rName, "/"), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoadBalancerExists(resourceName, &lb), + resource.TestCheckResourceAttr(resourceName, "health_check_path", "/"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLoadBalancerConfig_healthCheckPath(rName, "/healthcheck"), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoadBalancerExists(resourceName, &lb), + resource.TestCheckResourceAttr(resourceName, "health_check_path", "/healthcheck"), + ), + }, + }, + }) +} + +func TestAccLightsailLoadBalancer_Tags(t *testing.T) { + var lb1, lb2, lb3 lightsail.LoadBalancer + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_lightsail_lb.test" + + 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, + Steps: []resource.TestStep{ + { + Config: testAccLoadBalancerConfig_tags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoadBalancerExists(resourceName, &lb1), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLoadBalancerConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoadBalancerExists(resourceName, &lb2), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccLoadBalancerConfig_tags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoadBalancerExists(resourceName, &lb3), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + +func testAccCheckLoadBalancerExists(n string, lb *lightsail.LoadBalancer) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No LightsailLoadBalancer ID is set") + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).LightsailConn + + resp, err := tflightsail.FindLoadBalancerByName(context.Background(), conn, rs.Primary.ID) + + if err != nil { + return err + } + + if resp == nil { + return fmt.Errorf("Load Balancer %q does not exist", rs.Primary.ID) + } + + *lb = *resp + + return nil + } +} + +func TestAccLightsailLoadBalancer_disappears(t *testing.T) { + var lb lightsail.LoadBalancer + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_lightsail_lb.test" + + testDestroy := func(*terraform.State) error { + // reach out and DELETE the LoadBalancer + conn := acctest.Provider.Meta().(*conns.AWSClient).LightsailConn + _, err := conn.DeleteLoadBalancer(&lightsail.DeleteLoadBalancerInput{ + LoadBalancerName: aws.String(rName), + }) + + if err != nil { + return fmt.Errorf("error deleting Lightsail LoadBalancer in disappear test") + } + + // sleep 7 seconds to give it time, so we don't have to poll + time.Sleep(7 * time.Second) + + return nil + } + + 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: testAccCheckLoadBalancerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLoadBalancerConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoadBalancerExists(resourceName, &lb), + testDestroy, + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckLoadBalancerDestroy(s *terraform.State) error { + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_lightsail_lb" { + continue + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).LightsailConn + + _, err := tflightsail.FindLoadBalancerByName(context.Background(), conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return create.Error(names.Lightsail, create.ErrActionCheckingDestroyed, tflightsail.ResLoadBalancer, rs.Primary.ID, errors.New("still exists")) + } + + return nil +} + +func testAccLoadBalancerConfig_basic(rName string) string { + return fmt.Sprintf(` +resource "aws_lightsail_lb" "test" { + name = %[1]q + health_check_path = "/" + instance_port = "80" +} +`, rName) +} + +func testAccLoadBalancerConfig_healthCheckPath(rName string, rPath string) string { + return fmt.Sprintf(` +resource "aws_lightsail_lb" "test" { + name = %[1]q + health_check_path = %[2]q + instance_port = "80" +} +`, rName, rPath) +} + +func testAccLoadBalancerConfig_tags1(rName string, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_lightsail_lb" "test" { + name = %[1]q + health_check_path = "/" + instance_port = "80" + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1) +} + +func testAccLoadBalancerConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_lightsail_lb" "test" { + name = %[1]q + health_check_path = "/" + instance_port = "80" + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +} From ce6167cb12adf51a763543ad61e5ed7b8889069a Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 12:14:47 -0400 Subject: [PATCH 21/35] Lightsail: Amend lb remove d.SetId() --- internal/service/lightsail/lb.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/service/lightsail/lb.go b/internal/service/lightsail/lb.go index be47cff76ec6..c314eead682a 100644 --- a/internal/service/lightsail/lb.go +++ b/internal/service/lightsail/lb.go @@ -194,7 +194,6 @@ func resourceLoadBalancerUpdate(ctx context.Context, d *schema.ResourceData, met } op := out.Operations[0] - d.SetId(d.Get("name").(string)) err = waitOperation(conn, op.Id) if err != nil { @@ -236,7 +235,6 @@ func resourceLoadBalancerDelete(ctx context.Context, d *schema.ResourceData, met } op := out.Operations[0] - d.SetId(d.Get("name").(string)) err = waitOperation(conn, op.Id) if err != nil { From 23a85d34af5dedba258efc5eaaaa6e277f838f45 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 16:17:39 -0400 Subject: [PATCH 22/35] Docs: Add lightsail_lb resource docs --- website/docs/r/lightsail_lb.html.markdown | 54 +++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 website/docs/r/lightsail_lb.html.markdown diff --git a/website/docs/r/lightsail_lb.html.markdown b/website/docs/r/lightsail_lb.html.markdown new file mode 100644 index 000000000000..e99f4595c9c8 --- /dev/null +++ b/website/docs/r/lightsail_lb.html.markdown @@ -0,0 +1,54 @@ +--- +subcategory: "Lightsail" +layout: "aws" +page_title: "AWS: aws_lightsail_lb" +description: |- + Provides a Lightsail Load Balancer +--- + +# Resource: aws_lightsail_lb + +Creates a Lightsail load balancer resource. + +## Example Usage, creating a new load balancer + +```terraform +resource "aws_lightsail_lb" "test" { + name = "test-load-balancer" + health_check_path = "/" + instance_port = "80" + tags = { + foo = "bar" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the Lightsail load balancer. +* `instance_port` - (Required) The instance port the load balancer will connect. +* `health_check_path` - (Optional) The health check path of the load balancer. Default value "/". +* `tags` - (Optional) A map of tags to assign to the resource. To create a key-only tag, use an empty string as the value. If configured with a provider `default_tags` configuration block present, tags with matching keys will overwrite those defined at the provider-level. + +## Attributes Reference + +The following attributes are exported in addition to the arguments listed above: + +* `id` - The name used for this load balancer (matches `name`). +* `arn` - The ARN of the Lightsail load balancer. +* `created_at` - The timestamp when the load balancer was created. +* `dns_name` - The DNS name of the load balancer. +* `protocol` - The protocol of the load balancer. +* `public_ports` - The public ports of the load balancer. +* `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). + +## Import + +`aws_lightsail_lb` can be imported by using the name attribute, e.g., + +``` +$ terraform import aws_lightsail_lb.test example-load-balancer +``` From 6d5b368a9e5ca679f110e9952a58e626d07848e9 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 16:18:10 -0400 Subject: [PATCH 23/35] lightsail: Amend consts add ResLoadBalancerAttachment --- internal/service/lightsail/consts.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/internal/service/lightsail/consts.go b/internal/service/lightsail/consts.go index a381e6042b98..41c10167b557 100644 --- a/internal/service/lightsail/consts.go +++ b/internal/service/lightsail/consts.go @@ -1,9 +1,10 @@ package lightsail const ( - ResCertificate = "Certificate" - ResDatabase = "Database" - ResTags = "Tags" - ResDomainEntry = "Domain Entry" - ResLoadBalancer = "Load Balancer" + ResCertificate = "Certificate" + ResDatabase = "Database" + ResTags = "Tags" + ResDomainEntry = "Domain Entry" + ResLoadBalancer = "Load Balancer" + ResLoadBalancerAttachment = "Load Balancer Attachment" ) From 4aa9f69094161db4150abe7ddf68e63de2481e04 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 16:18:41 -0400 Subject: [PATCH 24/35] lightsail: Amend find Add FindLoadBalancerAttachmentById --- internal/service/lightsail/find.go | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/internal/service/lightsail/find.go b/internal/service/lightsail/find.go index 3fd994f36edc..cfcb486fb0d7 100644 --- a/internal/service/lightsail/find.go +++ b/internal/service/lightsail/find.go @@ -2,6 +2,7 @@ package lightsail import ( "context" + "errors" "strings" "github.com/aws/aws-sdk-go/aws" @@ -182,3 +183,46 @@ func FindLoadBalancerByName(ctx context.Context, conn *lightsail.Lightsail, name return lb, nil } + +func FindLoadBalancerAttachmentById(ctx context.Context, conn *lightsail.Lightsail, id string) (*string, error) { + + id_parts := strings.SplitN(id, ",", -1) + if len(id_parts) != 2 { + return nil, errors.New("invalid load balancer attachment id") + } + + lbName := id_parts[0] + iName := id_parts[1] + + in := &lightsail.GetLoadBalancerInput{LoadBalancerName: aws.String(lbName)} + out, err := conn.GetLoadBalancerWithContext(ctx, in) + + if tfawserr.ErrCodeEquals(err, lightsail.ErrCodeNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: in, + } + } + + if err != nil { + return nil, err + } + + var entry *string + entryExists := false + + for _, n := range out.LoadBalancer.InstanceHealthSummary { + if iName == aws.StringValue(n.InstanceName) { + entry = n.InstanceName + entryExists = true + break + } + } + + if !entryExists { + return nil, tfresource.NewEmptyResultError(in) + } + + return entry, nil + +} From 01d66ce1368725b8971065b8a4ac73e7cb56095b Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 16:19:01 -0400 Subject: [PATCH 25/35] lightsail: Add lb_attachment resource --- internal/provider/provider.go | 1 + internal/service/lightsail/lb_attachment.go | 152 ++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 internal/service/lightsail/lb_attachment.go diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 18dc5f465096..c474e6dae906 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -1716,6 +1716,7 @@ func New(_ context.Context) (*schema.Provider, error) { "aws_lightsail_instance_public_ports": lightsail.ResourceInstancePublicPorts(), "aws_lightsail_key_pair": lightsail.ResourceKeyPair(), "aws_lightsail_lb": lightsail.ResourceLoadBalancer(), + "aws_lightsail_lb_attachment": lightsail.ResourceLoadBalancerAttachment(), "aws_lightsail_static_ip": lightsail.ResourceStaticIP(), "aws_lightsail_static_ip_attachment": lightsail.ResourceStaticIPAttachment(), diff --git a/internal/service/lightsail/lb_attachment.go b/internal/service/lightsail/lb_attachment.go new file mode 100644 index 000000000000..9d0ddffd04f6 --- /dev/null +++ b/internal/service/lightsail/lb_attachment.go @@ -0,0 +1,152 @@ +package lightsail + +import ( + "context" + "errors" + "regexp" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/lightsail" + "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" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func ResourceLoadBalancerAttachment() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: resourceLoadBalancerAttachmentCreate, + ReadWithoutTimeout: resourceLoadBalancerAttachmentRead, + DeleteWithoutTimeout: resourceLoadBalancerAttachmentDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "lb_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(2, 255), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z]`), "must begin with an alphabetic character"), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9_\-.]+[^._\-]$`), "must contain only alphanumeric characters, underscores, hyphens, and dots"), + ), + }, + "instance_name": { + Type: schema.TypeString, + Set: schema.HashString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceLoadBalancerAttachmentCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).LightsailConn + + req := lightsail.AttachInstancesToLoadBalancerInput{ + LoadBalancerName: aws.String(d.Get("lb_name").(string)), + InstanceNames: aws.StringSlice([]string{d.Get("instance_name").(string)}), + } + + out, err := conn.AttachInstancesToLoadBalancerWithContext(ctx, &req) + + if err != nil { + return create.DiagError(names.Lightsail, lightsail.OperationTypeAttachInstancesToLoadBalancer, ResLoadBalancerAttachment, d.Get("name").(string), err) + } + + if len(out.Operations) == 0 { + return create.DiagError(names.Lightsail, lightsail.OperationTypeAttachInstancesToLoadBalancer, ResLoadBalancerAttachment, d.Get("name").(string), errors.New("No operations found for Attach Instances to Load Balancer request")) + } + + op := out.Operations[0] + + err = waitOperation(conn, op.Id) + + if err != nil { + return create.DiagError(names.Lightsail, lightsail.OperationTypeAttachInstancesToLoadBalancer, ResLoadBalancerAttachment, d.Get("name").(string), errors.New("Error waiting for Attach Instances to Load Balancer request operation")) + } + + // Generate an ID + vars := []string{ + d.Get("lb_name").(string), + d.Get("instance_name").(string), + } + + d.SetId(strings.Join(vars, ",")) + + return resourceLoadBalancerAttachmentRead(ctx, d, meta) +} + +func resourceLoadBalancerAttachmentRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).LightsailConn + + out, err := FindLoadBalancerAttachmentById(ctx, conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + create.LogNotFoundRemoveState(names.Lightsail, create.ErrActionReading, ResLoadBalancerAttachment, d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return create.DiagError(names.Lightsail, create.ErrActionReading, ResLoadBalancerAttachment, d.Id(), err) + } + + d.Set("instance_name", out) + d.Set("lb_name", expandLoadBalancerNameFromId(d.Id())) + + return nil +} + +func resourceLoadBalancerAttachmentDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).LightsailConn + + id_parts := strings.SplitN(d.Id(), ",", -1) + if len(id_parts) != 2 { + return nil + } + + lbName := id_parts[0] + iName := id_parts[1] + + in := lightsail.DetachInstancesFromLoadBalancerInput{ + LoadBalancerName: aws.String(lbName), + InstanceNames: aws.StringSlice([]string{iName}), + } + + out, err := conn.DetachInstancesFromLoadBalancerWithContext(ctx, &in) + + if err != nil { + return create.DiagError(names.Lightsail, lightsail.OperationTypeDetachInstancesFromLoadBalancer, ResLoadBalancerAttachment, d.Get("name").(string), err) + } + + if len(out.Operations) == 0 { + return create.DiagError(names.Lightsail, lightsail.OperationTypeDetachInstancesFromLoadBalancer, ResLoadBalancerAttachment, d.Get("name").(string), errors.New("No operations found for Detach Instances from Load Balancer request")) + } + + op := out.Operations[0] + + err = waitOperation(conn, op.Id) + + if err != nil { + return create.DiagError(names.Lightsail, lightsail.OperationTypeDetachInstancesFromLoadBalancer, ResLoadBalancerAttachment, d.Get("name").(string), errors.New("Error waiting for Instances to Detach from the Load Balancer request operation")) + } + + return nil +} + +func expandLoadBalancerNameFromId(id string) string { + + id_parts := strings.SplitN(id, ",", -1) + lbName := id_parts[0] + + return lbName +} From 08661197510616f71b5f774b286dc4210d673883 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 16:19:30 -0400 Subject: [PATCH 26/35] lightsail: Add lb_attachment_test --- .../service/lightsail/lb_attachment_test.go | 219 ++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 internal/service/lightsail/lb_attachment_test.go diff --git a/internal/service/lightsail/lb_attachment_test.go b/internal/service/lightsail/lb_attachment_test.go new file mode 100644 index 000000000000..00d67825520e --- /dev/null +++ b/internal/service/lightsail/lb_attachment_test.go @@ -0,0 +1,219 @@ +package lightsail_test + +import ( + "context" + "errors" + "fmt" + "log" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/lightsail" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/create" + tflightsail "github.com/hashicorp/terraform-provider-aws/internal/service/lightsail" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccLightsailLoadBalancerAttachment_basic(t *testing.T) { + resourceName := "aws_lightsail_lb_attachment.test" + lbName := sdkacctest.RandomWithPrefix("tf-acc-test") + liName := sdkacctest.RandomWithPrefix("tf-acc-test") + + 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: testAccCheckLoadBalancerAttachmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLoadBalancerAttachmentConfig_basic(lbName, liName), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoadBalancerAttachmentExists(resourceName, &liName), + resource.TestCheckResourceAttr(resourceName, "lb_name", lbName), + resource.TestCheckResourceAttr(resourceName, "instance_name", liName), + ), + }, + }, + }) +} + +func TestAccLightsailLoadBalancerAttachment_disappears(t *testing.T) { + resourceName := "aws_lightsail_lb_attachment.test" + lbName := sdkacctest.RandomWithPrefix("tf-acc-test") + liName := sdkacctest.RandomWithPrefix("tf-acc-test") + + testDestroy := func(*terraform.State) error { + // reach out and detach Instance from the Load Balancer + conn := acctest.Provider.Meta().(*conns.AWSClient).LightsailConn + + resp, err := conn.DetachInstancesFromLoadBalancer(&lightsail.DetachInstancesFromLoadBalancerInput{ + LoadBalancerName: aws.String(lbName), + InstanceNames: aws.StringSlice([]string{liName}), + }) + + if len(resp.Operations) == 0 { + return fmt.Errorf("No operations found for Detach Instances From Load Balancer request") + } + + op := resp.Operations[0] + + stateConf := &resource.StateChangeConf{ + Pending: []string{"Started"}, + Target: []string{"Completed", "Succeeded"}, + Refresh: resourceOperationRefreshFunc(op.Id, acctest.Provider.Meta()), + Timeout: 10 * time.Minute, + Delay: 5 * time.Second, + MinTimeout: 3 * time.Second, + } + + _, err = stateConf.WaitForState() + + if err != nil { + return fmt.Errorf("error detaching Lightsail instance from LoadBalancer in disappear test") + } + + return nil + } + + 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, + Steps: []resource.TestStep{ + { + Config: testAccLoadBalancerAttachmentConfig_basic(lbName, liName), + Check: resource.ComposeTestCheckFunc( + testAccCheckLoadBalancerAttachmentExists(resourceName, &liName), + testDestroy, + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckLoadBalancerAttachmentExists(n string, liName *string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("No LightsailLoadBalancerAttachment ID is set") + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).LightsailConn + + out, err := tflightsail.FindLoadBalancerAttachmentById(context.Background(), conn, rs.Primary.ID) + + if err != nil { + return err + } + + if out == nil { + return fmt.Errorf("Load Balancer %q does not exist", rs.Primary.ID) + } + + liName = out + + return nil + } +} + +func testAccCheckLoadBalancerAttachmentDestroy(s *terraform.State) error { + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_lightsail_lb_attachment" { + continue + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).LightsailConn + + _, err := tflightsail.FindLoadBalancerAttachmentById(context.Background(), conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return create.Error(names.Lightsail, create.ErrActionCheckingDestroyed, tflightsail.ResLoadBalancerAttachment, rs.Primary.ID, errors.New("still exists")) + } + + return nil +} + +func testAccLoadBalancerAttachmentConfig_basic(lbName string, liName string) string { + return fmt.Sprintf(` + data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } + } +resource "aws_lightsail_lb" "test" { + name = %[1]q + health_check_path = "/" + instance_port = "80" +} +resource "aws_lightsail_instance" "test" { + name = %[2]q + availability_zone = data.aws_availability_zones.available.names[0] + blueprint_id = "amazon_linux" + bundle_id = "nano_1_0" +} +resource "aws_lightsail_lb_attachment" "test" { + lb_name = aws_lightsail_lb.test.name + instance_name = aws_lightsail_instance.test.name +} +`, lbName, liName) +} + +// method to check the status of an Operation, which is returned from +// Create/Delete methods. +// Status's are an aws.OperationStatus enum: +// - NotStarted +// - Started +// - Failed +// - Completed +// - Succeeded (not documented?) +func resourceOperationRefreshFunc( + oid *string, meta interface{}) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + conn := meta.(*conns.AWSClient).LightsailConn + log.Printf("[DEBUG] Checking if Lightsail Operation (%s) is Completed", *oid) + o, err := conn.GetOperation(&lightsail.GetOperationInput{ + OperationId: oid, + }) + if err != nil { + return o, "FAILED", err + } + + if o.Operation == nil { + return nil, "Failed", fmt.Errorf("Error retrieving Operation info for operation (%s)", *oid) + } + + log.Printf("[DEBUG] Lightsail Operation (%s) is currently %q", *oid, *o.Operation.Status) + return o, *o.Operation.Status, nil + } +} From 3bbbd59e9f407f9571e58d39fc566354f4136e9e Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 16:19:53 -0400 Subject: [PATCH 27/35] lightsail: Amend lb Update functions to use context --- internal/service/lightsail/lb.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/service/lightsail/lb.go b/internal/service/lightsail/lb.go index c314eead682a..6ebb2d1345fd 100644 --- a/internal/service/lightsail/lb.go +++ b/internal/service/lightsail/lb.go @@ -108,7 +108,7 @@ func resourceLoadBalancerCreate(ctx context.Context, d *schema.ResourceData, met in.Tags = Tags(tags.IgnoreAWS()) } - out, err := conn.CreateLoadBalancer(&in) + out, err := conn.CreateLoadBalancerWithContext(ctx, &in) if err != nil { return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), err) @@ -222,7 +222,8 @@ func resourceLoadBalancerUpdate(ctx context.Context, d *schema.ResourceData, met func resourceLoadBalancerDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).LightsailConn - out, err := conn.DeleteLoadBalancer(&lightsail.DeleteLoadBalancerInput{ + + out, err := conn.DeleteLoadBalancerWithContext(ctx, &lightsail.DeleteLoadBalancerInput{ LoadBalancerName: aws.String(d.Id()), }) From 325636baa71fdfccb450cee41169118eaa6414a5 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 16:20:23 -0400 Subject: [PATCH 28/35] docs: Add lightsail_lb_attachment docs --- .../r/lightsail_lb_attachment.html.markdown | 66 +++++++++++++++++++ .../r/lightsail_load_balancer.html.markdown | 52 --------------- 2 files changed, 66 insertions(+), 52 deletions(-) create mode 100644 website/docs/r/lightsail_lb_attachment.html.markdown delete mode 100644 website/docs/r/lightsail_load_balancer.html.markdown diff --git a/website/docs/r/lightsail_lb_attachment.html.markdown b/website/docs/r/lightsail_lb_attachment.html.markdown new file mode 100644 index 000000000000..47c5fb7ae65f --- /dev/null +++ b/website/docs/r/lightsail_lb_attachment.html.markdown @@ -0,0 +1,66 @@ +--- +subcategory: "Lightsail" +layout: "aws" +page_title: "AWS: aws_lightsail_lb_attachment" +description: |- + Attaches a Lightsail Instance to a Lightsail Load Balancer +--- + +# Resource: aws_lightsail_lb_attachment + +Attaches a Lightsail Instance to a Lightsail Load Balancer. + +## Example Usage + +```terraform +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +resource "aws_lightsail_lb" "test" { + name = "test-load-balancer" + health_check_path = "/" + instance_port = "80" + tags = { + foo = "bar" + } +} + +resource "aws_lightsail_instance" "test" { + name = "test-instance" + availability_zone = data.aws_availability_zones.available.names[0] + blueprint_id = "amazon_linux" + bundle_id = "nano_1_0" +} + +resource "aws_lightsail_lb_attachment" "test" { + lb_name = aws_lightsail_lb.test.name + instance_name = aws_lightsail_instance.test.name +} +``` + +## Argument Reference + +The following arguments are supported: + +* `lb_name` - (Required) The name of the Lightsail load balancer. +* `instance_name` - (Required) The name of the instance to attach to the load balancer. + +## Attributes Reference + +The following attributes are exported in addition to the arguments listed above: + +* `id` - A combination of attributes to create a unique id: `lb_name`,`instance_name` + +## Import + +`aws_lightsail_lb_attachment` can be imported by using the name attribute, e.g., + +``` +$ terraform import aws_lightsail_lb_attachment.test example-load-balancer,example-instance +``` diff --git a/website/docs/r/lightsail_load_balancer.html.markdown b/website/docs/r/lightsail_load_balancer.html.markdown deleted file mode 100644 index 8a49945cee8d..000000000000 --- a/website/docs/r/lightsail_load_balancer.html.markdown +++ /dev/null @@ -1,52 +0,0 @@ ---- -subcategory: "Lightsail" -layout: "aws" -page_title: "AWS: aws_lightsail_load_balancer" -description: |- - Provides a Lightsail Load Balancer ---- - -# Resource: aws_lightsail_load_balancer - -Creates a Lightsail load balancer resource. - -~> **Note:** Lightsail is currently only supported in a limited number of AWS Regions, please see ["Regions and Availability Zones in Amazon Lightsail"](https://lightsail.aws.amazon.com/ls/docs/overview/article/understanding-regions-and-availability-zones-in-amazon-lightsail) for more details - -## Example Usage, creating a new load balancer - -```hcl -resource "aws_lightsail_load_balancer" "load_balancer_test" { - name = "test-load-balancer" - health_check_path = "/" - instance_port = "80" - tags = { - foo = "bar" - } -} -``` - -## Argument Reference - -The following arguments are supported: - -* `name` - (Required) The name of the Lightsail load balancer. -* `instance_port` - (Required) The instance port the load balancer will connect. -* `health_check_path` - (Optional) The health check path of the load balancer. Default value "/". -* `tags` - (Optional) A mapping of tags to assign to the resource. - -## Attributes Reference - -The following attributes are exported in addition to the arguments listed above: - -* `arn` - The ARN of the Lightsail load balancer. -* `created_at` - The timestamp when the load balancer was created. -* `dns_name` - The DNS name of the load balancer. -* `id` - The name used for this load balancer. -* `protocol` - The protocol of the load balancer. -* `public_ports` - The public ports of the load balancer. - -Lightsail Load Balancers can be imported using their name, e.g. - -``` -$ terraform import aws_lightsail_load_balancer.website_load_balancer_ 'example-load-balancer' -``` From 5ef7cedc2ceee423f784b577dcac4d821a7f0ab2 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 16:23:05 -0400 Subject: [PATCH 29/35] lightsail: terrafmt tests --- .../service/lightsail/lb_attachment_test.go | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/service/lightsail/lb_attachment_test.go b/internal/service/lightsail/lb_attachment_test.go index 00d67825520e..601b873e68ec 100644 --- a/internal/service/lightsail/lb_attachment_test.go +++ b/internal/service/lightsail/lb_attachment_test.go @@ -163,14 +163,14 @@ func testAccCheckLoadBalancerAttachmentDestroy(s *terraform.State) error { func testAccLoadBalancerAttachmentConfig_basic(lbName string, liName string) string { return fmt.Sprintf(` - data "aws_availability_zones" "available" { - state = "available" - - filter { - name = "opt-in-status" - values = ["opt-in-not-required"] - } - } +data "aws_availability_zones" "available" { + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} resource "aws_lightsail_lb" "test" { name = %[1]q health_check_path = "/" @@ -183,8 +183,8 @@ resource "aws_lightsail_instance" "test" { bundle_id = "nano_1_0" } resource "aws_lightsail_lb_attachment" "test" { - lb_name = aws_lightsail_lb.test.name - instance_name = aws_lightsail_instance.test.name + lb_name = aws_lightsail_lb.test.name + instance_name = aws_lightsail_instance.test.name } `, lbName, liName) } From b5635b8f082753cb8f5ed09b5ebf395607f763c8 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 16:33:53 -0400 Subject: [PATCH 30/35] lightsail: Amend lb_attachement_test testdestroy * moved from testDestroy to acctest.CheckResourceDisappears --- .../service/lightsail/lb_attachment_test.go | 67 +------------------ 1 file changed, 1 insertion(+), 66 deletions(-) diff --git a/internal/service/lightsail/lb_attachment_test.go b/internal/service/lightsail/lb_attachment_test.go index 601b873e68ec..c800b65ccc44 100644 --- a/internal/service/lightsail/lb_attachment_test.go +++ b/internal/service/lightsail/lb_attachment_test.go @@ -4,11 +4,8 @@ import ( "context" "errors" "fmt" - "log" "testing" - "time" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/lightsail" sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -53,39 +50,6 @@ func TestAccLightsailLoadBalancerAttachment_disappears(t *testing.T) { lbName := sdkacctest.RandomWithPrefix("tf-acc-test") liName := sdkacctest.RandomWithPrefix("tf-acc-test") - testDestroy := func(*terraform.State) error { - // reach out and detach Instance from the Load Balancer - conn := acctest.Provider.Meta().(*conns.AWSClient).LightsailConn - - resp, err := conn.DetachInstancesFromLoadBalancer(&lightsail.DetachInstancesFromLoadBalancerInput{ - LoadBalancerName: aws.String(lbName), - InstanceNames: aws.StringSlice([]string{liName}), - }) - - if len(resp.Operations) == 0 { - return fmt.Errorf("No operations found for Detach Instances From Load Balancer request") - } - - op := resp.Operations[0] - - stateConf := &resource.StateChangeConf{ - Pending: []string{"Started"}, - Target: []string{"Completed", "Succeeded"}, - Refresh: resourceOperationRefreshFunc(op.Id, acctest.Provider.Meta()), - Timeout: 10 * time.Minute, - Delay: 5 * time.Second, - MinTimeout: 3 * time.Second, - } - - _, err = stateConf.WaitForState() - - if err != nil { - return fmt.Errorf("error detaching Lightsail instance from LoadBalancer in disappear test") - } - - return nil - } - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) @@ -99,7 +63,7 @@ func TestAccLightsailLoadBalancerAttachment_disappears(t *testing.T) { Config: testAccLoadBalancerAttachmentConfig_basic(lbName, liName), Check: resource.ComposeTestCheckFunc( testAccCheckLoadBalancerAttachmentExists(resourceName, &liName), - testDestroy, + acctest.CheckResourceDisappears(acctest.Provider, tflightsail.ResourceLoadBalancerAttachment(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -188,32 +152,3 @@ resource "aws_lightsail_lb_attachment" "test" { } `, lbName, liName) } - -// method to check the status of an Operation, which is returned from -// Create/Delete methods. -// Status's are an aws.OperationStatus enum: -// - NotStarted -// - Started -// - Failed -// - Completed -// - Succeeded (not documented?) -func resourceOperationRefreshFunc( - oid *string, meta interface{}) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - conn := meta.(*conns.AWSClient).LightsailConn - log.Printf("[DEBUG] Checking if Lightsail Operation (%s) is Completed", *oid) - o, err := conn.GetOperation(&lightsail.GetOperationInput{ - OperationId: oid, - }) - if err != nil { - return o, "FAILED", err - } - - if o.Operation == nil { - return nil, "Failed", fmt.Errorf("Error retrieving Operation info for operation (%s)", *oid) - } - - log.Printf("[DEBUG] Lightsail Operation (%s) is currently %q", *oid, *o.Operation.Status) - return o, *o.Operation.Status, nil - } -} From 13c380a0cfbfe6d01f3d49b60c8f581971525352 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 16:36:04 -0400 Subject: [PATCH 31/35] changelog: add 27339 changelog --- .changelog/27339.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/27339.txt diff --git a/.changelog/27339.txt b/.changelog/27339.txt new file mode 100644 index 000000000000..0c7dccd4a4f7 --- /dev/null +++ b/.changelog/27339.txt @@ -0,0 +1,7 @@ +```release-note:new-resource +aws_lightsail_lb +``` + +```release-note:new-resource +aws_lightsail_lb_attachment +``` \ No newline at end of file From f5e8a55c01e3aa7160ffbeee65ff1791a9da853b Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Wed, 19 Oct 2022 17:44:57 -0400 Subject: [PATCH 32/35] lightsail: Amend lb_test and lb_attachment_test Add checkdestroy --- internal/service/lightsail/lb_attachment.go | 1 - internal/service/lightsail/lb_attachment_test.go | 1 + internal/service/lightsail/lb_test.go | 2 ++ 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/service/lightsail/lb_attachment.go b/internal/service/lightsail/lb_attachment.go index 9d0ddffd04f6..e6f4f09fbf5e 100644 --- a/internal/service/lightsail/lb_attachment.go +++ b/internal/service/lightsail/lb_attachment.go @@ -40,7 +40,6 @@ func ResourceLoadBalancerAttachment() *schema.Resource { }, "instance_name": { Type: schema.TypeString, - Set: schema.HashString, Required: true, ForceNew: true, }, diff --git a/internal/service/lightsail/lb_attachment_test.go b/internal/service/lightsail/lb_attachment_test.go index c800b65ccc44..38cc91be7a95 100644 --- a/internal/service/lightsail/lb_attachment_test.go +++ b/internal/service/lightsail/lb_attachment_test.go @@ -58,6 +58,7 @@ func TestAccLightsailLoadBalancerAttachment_disappears(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, lightsail.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckLoadBalancerAttachmentDestroy, Steps: []resource.TestStep{ { Config: testAccLoadBalancerAttachmentConfig_basic(lbName, liName), diff --git a/internal/service/lightsail/lb_test.go b/internal/service/lightsail/lb_test.go index d229635af81a..5fe5363c4e35 100644 --- a/internal/service/lightsail/lb_test.go +++ b/internal/service/lightsail/lb_test.go @@ -113,6 +113,7 @@ func TestAccLightsailLoadBalancer_HealthCheckPath(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, lightsail.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckLoadBalancerDestroy, Steps: []resource.TestStep{ { Config: testAccLoadBalancerConfig_healthCheckPath(rName, "/"), @@ -150,6 +151,7 @@ func TestAccLightsailLoadBalancer_Tags(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, lightsail.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckLoadBalancerDestroy, Steps: []resource.TestStep{ { Config: testAccLoadBalancerConfig_tags1(rName, "key1", "value1"), From 5e79a0b8639986bc9e7159b3f2315dd36fdf01c8 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Thu, 20 Oct 2022 08:44:31 -0400 Subject: [PATCH 33/35] lightsail: Amend lb and lb_attachment * move import to use new context function --- internal/service/lightsail/lb.go | 2 +- internal/service/lightsail/lb_attachment.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/lightsail/lb.go b/internal/service/lightsail/lb.go index 6ebb2d1345fd..c1379b405ad6 100644 --- a/internal/service/lightsail/lb.go +++ b/internal/service/lightsail/lb.go @@ -27,7 +27,7 @@ func ResourceLoadBalancer() *schema.Resource { DeleteWithoutTimeout: resourceLoadBalancerDelete, Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, + StateContext: schema.ImportStatePassthroughContext, }, Schema: map[string]*schema.Schema{ diff --git a/internal/service/lightsail/lb_attachment.go b/internal/service/lightsail/lb_attachment.go index e6f4f09fbf5e..16e9ce3a600b 100644 --- a/internal/service/lightsail/lb_attachment.go +++ b/internal/service/lightsail/lb_attachment.go @@ -24,7 +24,7 @@ func ResourceLoadBalancerAttachment() *schema.Resource { DeleteWithoutTimeout: resourceLoadBalancerAttachmentDelete, Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, + StateContext: schema.ImportStatePassthroughContext, }, Schema: map[string]*schema.Schema{ From e9b5e1aff970753a5e5e17924afe6d1ddc66e7c2 Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Thu, 20 Oct 2022 08:44:52 -0400 Subject: [PATCH 34/35] docs: lightsail lb and lb_attachment lint fix --- website/docs/r/lightsail_lb.html.markdown | 4 ++-- website/docs/r/lightsail_lb_attachment.html.markdown | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/r/lightsail_lb.html.markdown b/website/docs/r/lightsail_lb.html.markdown index e99f4595c9c8..7eae87b16bd4 100644 --- a/website/docs/r/lightsail_lb.html.markdown +++ b/website/docs/r/lightsail_lb.html.markdown @@ -10,7 +10,7 @@ description: |- Creates a Lightsail load balancer resource. -## Example Usage, creating a new load balancer +## Example Usage ```terraform resource "aws_lightsail_lb" "test" { @@ -34,7 +34,7 @@ The following arguments are supported: ## Attributes Reference -The following attributes are exported in addition to the arguments listed above: +In addition to all arguments above, the following attributes are exported: * `id` - The name used for this load balancer (matches `name`). * `arn` - The ARN of the Lightsail load balancer. diff --git a/website/docs/r/lightsail_lb_attachment.html.markdown b/website/docs/r/lightsail_lb_attachment.html.markdown index 47c5fb7ae65f..290d19bcc10b 100644 --- a/website/docs/r/lightsail_lb_attachment.html.markdown +++ b/website/docs/r/lightsail_lb_attachment.html.markdown @@ -53,7 +53,7 @@ The following arguments are supported: ## Attributes Reference -The following attributes are exported in addition to the arguments listed above: +In addition to all arguments above, the following attributes are exported: * `id` - A combination of attributes to create a unique id: `lb_name`,`instance_name` From d59ab53ceba8df0ccb28b391fcbd900d5f85a5cb Mon Sep 17 00:00:00 2001 From: Brittan DeYoung <32572259+brittandeyoung@users.noreply.github.com> Date: Thu, 20 Oct 2022 08:50:07 -0400 Subject: [PATCH 35/35] lightsail: Amend lb and lb_attachment golangci-lint * remove extra new lines flagged by golangci-lint --- internal/service/lightsail/find.go | 4 ---- internal/service/lightsail/lb_attachment.go | 1 - internal/service/lightsail/lb_attachment_test.go | 1 - internal/service/lightsail/lb_test.go | 1 - 4 files changed, 7 deletions(-) diff --git a/internal/service/lightsail/find.go b/internal/service/lightsail/find.go index 7f90b3c0ee18..2130cdfe4fb7 100644 --- a/internal/service/lightsail/find.go +++ b/internal/service/lightsail/find.go @@ -158,7 +158,6 @@ func FindDomainEntryById(ctx context.Context, conn *lightsail.Lightsail, id stri } func FindLoadBalancerByName(ctx context.Context, conn *lightsail.Lightsail, name string) (*lightsail.LoadBalancer, error) { - in := &lightsail.GetLoadBalancerInput{LoadBalancerName: aws.String(name)} out, err := conn.GetLoadBalancerWithContext(ctx, in) @@ -180,11 +179,9 @@ func FindLoadBalancerByName(ctx context.Context, conn *lightsail.Lightsail, name lb := out.LoadBalancer return lb, nil - } func FindLoadBalancerAttachmentById(ctx context.Context, conn *lightsail.Lightsail, id string) (*string, error) { - id_parts := strings.SplitN(id, ",", -1) if len(id_parts) != 2 { return nil, errors.New("invalid load balancer attachment id") @@ -223,5 +220,4 @@ func FindLoadBalancerAttachmentById(ctx context.Context, conn *lightsail.Lightsa } return entry, nil - } diff --git a/internal/service/lightsail/lb_attachment.go b/internal/service/lightsail/lb_attachment.go index 16e9ce3a600b..538ec7ab9a4c 100644 --- a/internal/service/lightsail/lb_attachment.go +++ b/internal/service/lightsail/lb_attachment.go @@ -143,7 +143,6 @@ func resourceLoadBalancerAttachmentDelete(ctx context.Context, d *schema.Resourc } func expandLoadBalancerNameFromId(id string) string { - id_parts := strings.SplitN(id, ",", -1) lbName := id_parts[0] diff --git a/internal/service/lightsail/lb_attachment_test.go b/internal/service/lightsail/lb_attachment_test.go index 38cc91be7a95..93babd30a8a7 100644 --- a/internal/service/lightsail/lb_attachment_test.go +++ b/internal/service/lightsail/lb_attachment_test.go @@ -102,7 +102,6 @@ func testAccCheckLoadBalancerAttachmentExists(n string, liName *string) resource } func testAccCheckLoadBalancerAttachmentDestroy(s *terraform.State) error { - for _, rs := range s.RootModule().Resources { if rs.Type != "aws_lightsail_lb_attachment" { continue diff --git a/internal/service/lightsail/lb_test.go b/internal/service/lightsail/lb_test.go index 5fe5363c4e35..8aef0668b770 100644 --- a/internal/service/lightsail/lb_test.go +++ b/internal/service/lightsail/lb_test.go @@ -261,7 +261,6 @@ func TestAccLightsailLoadBalancer_disappears(t *testing.T) { } func testAccCheckLoadBalancerDestroy(s *terraform.State) error { - for _, rs := range s.RootModule().Resources { if rs.Type != "aws_lightsail_lb" { continue