Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

New Resource: aws_lightsail_domain_entry #27309

Merged
merged 15 commits into from
Oct 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/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