Skip to content

Commit

Permalink
Merge pull request #27309 from brittandeyoung/aws_lightsail_domain_entry
Browse files Browse the repository at this point in the history
New Resource: `aws_lightsail_domain_entry`
  • Loading branch information
ewbankkit authored Oct 19, 2022
2 parents ade4b69 + 20e5d3e commit 5b85a57
Show file tree
Hide file tree
Showing 7 changed files with 479 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/27309.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_lightsail_domain_entry
```
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -1711,6 +1711,7 @@ func New(_ context.Context) (*schema.Provider, error) {
"aws_lightsail_container_service_deployment_version": lightsail.ResourceContainerServiceDeploymentVersion(),
"aws_lightsail_database": lightsail.ResourceDatabase(),
"aws_lightsail_domain": lightsail.ResourceDomain(),
"aws_lightsail_domain_entry": lightsail.ResourceDomainEntry(),
"aws_lightsail_instance": lightsail.ResourceInstance(),
"aws_lightsail_instance_public_ports": lightsail.ResourceInstancePublicPorts(),
"aws_lightsail_key_pair": lightsail.ResourceKeyPair(),
Expand Down
1 change: 1 addition & 0 deletions internal/service/lightsail/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ const (
ResCertificate = "Certificate"
ResDatabase = "Database"
ResTags = "Tags"
ResDomainEntry = "Domain Entry"
)
207 changes: 207 additions & 0 deletions internal/service/lightsail/domain_entry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
package lightsail

import (
"context"
"errors"
"fmt"
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/lightsail"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/create"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/names"
)

func ResourceDomainEntry() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceDomainEntryCreate,
ReadWithoutTimeout: resourceDomainEntryRead,
DeleteWithoutTimeout: resourceDomainEntryDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: map[string]*schema.Schema{
"domain_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"is_alias": {
Type: schema.TypeBool,
Optional: true,
Default: false,
ForceNew: true,
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"target": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"type": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{
"A",
"CNAME",
"MX",
"NS",
"SOA",
"SRV",
"TXT",
}, false),
ForceNew: true,
},
},
}
}

func resourceDomainEntryCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).LightsailConn

req := &lightsail.CreateDomainEntryInput{
DomainName: aws.String(d.Get("domain_name").(string)),

DomainEntry: &lightsail.DomainEntry{
IsAlias: aws.Bool(d.Get("is_alias").(bool)),
Name: aws.String(expandDomainEntryName(d.Get("name").(string), d.Get("domain_name").(string))),
Target: aws.String(d.Get("target").(string)),
Type: aws.String(d.Get("type").(string)),
},
}

resp, err := conn.CreateDomainEntry(req)

if err != nil {
return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateDomain, ResDomainEntry, d.Get("name").(string), err)
}

op := resp.Operation

err = waitOperation(conn, op.Id)
if err != nil {
return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateDomain, ResDomainEntry, d.Get("name").(string), errors.New("Error waiting for Create DomainEntry request operation"))
}

// Generate an ID
vars := []string{
d.Get("name").(string),
d.Get("domain_name").(string),
d.Get("type").(string),
d.Get("target").(string),
}

d.SetId(strings.Join(vars, "_"))

return resourceDomainEntryRead(ctx, d, meta)
}

func resourceDomainEntryRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).LightsailConn

entry, err := FindDomainEntryById(ctx, conn, d.Id())

if !d.IsNewResource() && tfresource.NotFound(err) {
create.LogNotFoundRemoveState(names.Lightsail, create.ErrActionReading, ResDomainEntry, d.Id())
d.SetId("")
return nil
}

if err != nil {
return create.DiagError(names.Lightsail, create.ErrActionReading, ResDomainEntry, d.Id(), err)
}

domainName := expandDomainNameFromId(d.Id())

d.Set("name", flattenDomainEntryName(aws.StringValue(entry.Name), domainName))
d.Set("domain_name", domainName)
d.Set("type", entry.Type)
d.Set("is_alias", entry.IsAlias)
d.Set("target", entry.Target)

return nil
}

func resourceDomainEntryDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).LightsailConn

resp, err := conn.DeleteDomainEntry(&lightsail.DeleteDomainEntryInput{
DomainName: aws.String(expandDomainNameFromId(d.Id())),
DomainEntry: expandDomainEntry(d.Id()),
})

if err != nil && tfawserr.ErrCodeEquals(err, lightsail.ErrCodeNotFoundException) {
return nil
}

if err != nil {
return create.DiagError(names.Lightsail, create.ErrActionDeleting, ResDomainEntry, d.Id(), err)
}

op := resp.Operation

err = waitOperation(conn, op.Id)
if err != nil {
return create.DiagError(names.Lightsail, lightsail.OperationTypeDeleteDomain, ResDomainEntry, d.Get("name").(string), errors.New("Error waiting for Delete DomainEntry request operation"))
}

return nil
}

func expandDomainEntry(id string) *lightsail.DomainEntry {

id_parts := strings.SplitN(id, "_", -1)
name := id_parts[0]
domainName := id_parts[1]
recordType := id_parts[2]
recordTarget := id_parts[3]

entry := &lightsail.DomainEntry{
Name: aws.String(expandDomainEntryName(name, domainName)),
Type: aws.String(recordType),
Target: aws.String(recordTarget),
}

return entry
}

func expandDomainNameFromId(id string) string {

id_parts := strings.SplitN(id, "_", -1)
domainName := id_parts[1]

return domainName
}

func expandDomainEntryName(name, domainName string) string {
rn := strings.ToLower(strings.TrimSuffix(name, "."))
domainName = strings.TrimSuffix(domainName, ".")
if !strings.HasSuffix(rn, domainName) {
if len(name) == 0 {
rn = domainName
} else {
rn = strings.Join([]string{rn, domainName}, ".")
}
}
return rn
}

func flattenDomainEntryName(name, domainName string) string {
rn := strings.ToLower(strings.TrimSuffix(name, "."))
domainName = strings.TrimSuffix(domainName, ".")
if strings.HasSuffix(rn, domainName) {
rn = strings.TrimSuffix(rn, fmt.Sprintf(".%s", domainName))
}
return rn
}
168 changes: 168 additions & 0 deletions internal/service/lightsail/domain_entry_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package lightsail_test

import (
"context"
"errors"
"fmt"
"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 TestAccLightsailDomainEntry_basic(t *testing.T) {
var domainEntry lightsail.DomainEntry
resourceName := "aws_lightsail_domain_entry.test"
domainName := acctest.RandomDomainName()
domainEntryName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t); testAccPreCheckDomain(t) },
ErrorCheck: acctest.ErrorCheck(t, lightsail.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckDomainEntryDestroy,
Steps: []resource.TestStep{
{
Config: testAccDomainEntryConfig_basic(domainName, domainEntryName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckDomainEntryExists(resourceName, &domainEntry),
resource.TestCheckResourceAttr(resourceName, "domain_name", domainName),
resource.TestCheckResourceAttr(resourceName, "name", domainEntryName),
resource.TestCheckResourceAttr(resourceName, "target", "127.0.0.1"),
resource.TestCheckResourceAttr(resourceName, "type", "A"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccLightsailDomainEntry_disappears(t *testing.T) {
var domainEntry lightsail.DomainEntry
resourceName := "aws_lightsail_domain_entry.test"
domainName := acctest.RandomDomainName()
domainEntryName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

testDestroy := func(*terraform.State) error {
conn := testAccProviderLightsailDomain.Meta().(*conns.AWSClient).LightsailConn
_, err := conn.DeleteDomainEntry(&lightsail.DeleteDomainEntryInput{
DomainName: aws.String(domainName),
DomainEntry: &lightsail.DomainEntry{
Name: aws.String(fmt.Sprintf("%s.%s", domainEntryName, domainName)),
Type: aws.String("A"),
Target: aws.String("127.0.0.1"),
},
})

if err != nil {
return fmt.Errorf("error deleting Lightsail Domain Entry 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); testAccPreCheckDomain(t) },
ErrorCheck: acctest.ErrorCheck(t, lightsail.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckDomainEntryDestroy,
Steps: []resource.TestStep{
{
Config: testAccDomainEntryConfig_basic(domainName, domainEntryName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckDomainEntryExists(resourceName, &domainEntry),
testDestroy,
),
ExpectNonEmptyPlan: true,
},
},
})
}

func testAccCheckDomainEntryExists(n string, domainEntry *lightsail.DomainEntry) 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 Lightsail Domain Entry ID is set")
}

conn := testAccProviderLightsailDomain.Meta().(*conns.AWSClient).LightsailConn

resp, err := tflightsail.FindDomainEntryById(context.Background(), conn, rs.Primary.ID)

if err != nil {
return err
}

if resp == nil {
return fmt.Errorf("DomainEntry %q does not exist", rs.Primary.ID)
}

*domainEntry = *resp

return nil
}
}

func testAccCheckDomainEntryDestroy(s *terraform.State) error {

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_lightsail_domain_entry" {
continue
}

conn := testAccProviderLightsailDomain.Meta().(*conns.AWSClient).LightsailConn

_, err := tflightsail.FindDomainEntryById(context.Background(), conn, rs.Primary.ID)

if tfresource.NotFound(err) {
continue
}

if err != nil {
return err
}

return create.Error(names.Lightsail, create.ErrActionCheckingDestroyed, tflightsail.ResDomainEntry, rs.Primary.ID, errors.New("still exists"))
}

return nil
}

func testAccDomainEntryConfig_basic(domainName string, domainEntryName string) string {
return acctest.ConfigCompose(
testAccDomainRegionProviderConfig(),
fmt.Sprintf(`
resource "aws_lightsail_domain" "test" {
domain_name = %[1]q
}
resource "aws_lightsail_domain_entry" "test" {
domain_name = aws_lightsail_domain.test.id
name = %[2]q
type = "A"
target = "127.0.0.1"
}
`, domainName, domainEntryName))
}
Loading

0 comments on commit 5b85a57

Please sign in to comment.