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

rd/efs_mount_target - add az specific dns name + attributes #13650

Merged
merged 2 commits into from
Jun 17, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 25 additions & 6 deletions aws/data_source_aws_efs_mount_target.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ func dataSourceAwsEfsMountTarget() *schema.Resource {
"security_groups": {
Type: schema.TypeSet,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
Computed: true,
},
"subnet_id": {
Expand All @@ -49,19 +48,35 @@ func dataSourceAwsEfsMountTarget() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"mount_target_dns_name": {
Type: schema.TypeString,
Computed: true,
},
"availability_zone_name": {
Type: schema.TypeString,
Computed: true,
},
"availability_zone_id": {
Type: schema.TypeString,
Computed: true,
},
"owner_id": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func dataSourceAwsEfsMountTargetRead(d *schema.ResourceData, meta interface{}) error {
efsconn := meta.(*AWSClient).efsconn
conn := meta.(*AWSClient).efsconn

describeEfsOpts := &efs.DescribeMountTargetsInput{
MountTargetId: aws.String(d.Get("mount_target_id").(string)),
}

log.Printf("[DEBUG] Reading EFS Mount Target: %s", describeEfsOpts)
resp, err := efsconn.DescribeMountTargets(describeEfsOpts)
resp, err := conn.DescribeMountTargets(describeEfsOpts)
if err != nil {
return fmt.Errorf("Error retrieving EFS Mount Target: %s", err)
}
Expand All @@ -73,7 +88,7 @@ func dataSourceAwsEfsMountTargetRead(d *schema.ResourceData, meta interface{}) e

log.Printf("[DEBUG] Found EFS mount target: %#v", mt)

d.SetId(*mt.MountTargetId)
d.SetId(aws.StringValue(mt.MountTargetId))

fsARN := arn.ARN{
AccountID: meta.(*AWSClient).accountid,
Expand All @@ -88,19 +103,23 @@ func dataSourceAwsEfsMountTargetRead(d *schema.ResourceData, meta interface{}) e
d.Set("ip_address", mt.IpAddress)
d.Set("subnet_id", mt.SubnetId)
d.Set("network_interface_id", mt.NetworkInterfaceId)
d.Set("availability_zone_name", mt.AvailabilityZoneName)
d.Set("availability_zone_id", mt.AvailabilityZoneId)
d.Set("owner_id", mt.OwnerId)

sgResp, err := efsconn.DescribeMountTargetSecurityGroups(&efs.DescribeMountTargetSecurityGroupsInput{
sgResp, err := conn.DescribeMountTargetSecurityGroups(&efs.DescribeMountTargetSecurityGroupsInput{
MountTargetId: aws.String(d.Id()),
})
if err != nil {
return err
}
err = d.Set("security_groups", schema.NewSet(schema.HashString, flattenStringList(sgResp.SecurityGroups)))
err = d.Set("security_groups", flattenStringSet(sgResp.SecurityGroups))
if err != nil {
return err
}

d.Set("dns_name", meta.(*AWSClient).RegionalHostname(fmt.Sprintf("%s.efs", aws.StringValue(mt.FileSystemId))))
d.Set("mount_target_dns_name", meta.(*AWSClient).RegionalHostname(fmt.Sprintf("%s.%s.efs", aws.StringValue(mt.AvailabilityZoneName), aws.StringValue(mt.FileSystemId))))

return nil
}
56 changes: 38 additions & 18 deletions aws/data_source_aws_efs_mount_target_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,26 @@ import (

func TestAccDataSourceAwsEfsMountTargetByMountTargetId(t *testing.T) {
rName := acctest.RandString(10)
dataSourceName := "data.aws_efs_mount_target.test"
resourceName := "aws_efs_mount_target.test"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccAwsEfsMountTargetConfigByMountTargetId(rName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrPair("data.aws_efs_mount_target.by_mount_target_id", "file_system_arn", "aws_efs_mount_target.alpha", "file_system_arn"),
resource.TestCheckResourceAttrSet("data.aws_efs_mount_target.by_mount_target_id", "file_system_id"),
resource.TestCheckResourceAttrSet("data.aws_efs_mount_target.by_mount_target_id", "ip_address"),
resource.TestCheckResourceAttrSet("data.aws_efs_mount_target.by_mount_target_id", "subnet_id"),
resource.TestCheckResourceAttrSet("data.aws_efs_mount_target.by_mount_target_id", "network_interface_id"),
resource.TestCheckResourceAttrSet("data.aws_efs_mount_target.by_mount_target_id", "dns_name"),
resource.TestCheckResourceAttrPair(dataSourceName, "file_system_arn", resourceName, "file_system_arn"),
resource.TestCheckResourceAttrPair(dataSourceName, "file_system_id", resourceName, "file_system_id"),
resource.TestCheckResourceAttrPair(dataSourceName, "ip_address", resourceName, "ip_address"),
resource.TestCheckResourceAttrPair(dataSourceName, "subnet_id", resourceName, "subnet_id"),
resource.TestCheckResourceAttrPair(dataSourceName, "network_interface_id", resourceName, "network_interface_id"),
resource.TestCheckResourceAttrPair(dataSourceName, "dns_name", resourceName, "dns_name"),
resource.TestCheckResourceAttrPair(dataSourceName, "mount_target_dns_name", resourceName, "mount_target_dns_name"),
resource.TestCheckResourceAttrPair(dataSourceName, "availability_zone_name", resourceName, "availability_zone_name"),
resource.TestCheckResourceAttrPair(dataSourceName, "availability_zone_id", resourceName, "availability_zone_id"),
resource.TestCheckResourceAttrPair(dataSourceName, "owner_id", resourceName, "owner_id"),
resource.TestCheckResourceAttrPair(dataSourceName, "security_groups", resourceName, "security_groups"),
),
},
},
Expand All @@ -31,35 +38,48 @@ func TestAccDataSourceAwsEfsMountTargetByMountTargetId(t *testing.T) {

func testAccAwsEfsMountTargetConfigByMountTargetId(ct string) string {
return fmt.Sprintf(`
resource "aws_efs_file_system" "foo" {
data "aws_availability_zones" "available" {
state = "available"

filter {
name = "opt-in-status"
values = ["opt-in-not-required"]
}
}

resource "aws_efs_file_system" "test" {
creation_token = "%s"

tags = {
Name = "tf-acc-efs-mount-target-test"
}
}

resource "aws_efs_mount_target" "alpha" {
file_system_id = "${aws_efs_file_system.foo.id}"
subnet_id = "${aws_subnet.alpha.id}"
resource "aws_efs_mount_target" "test" {
file_system_id = "${aws_efs_file_system.test.id}"
subnet_id = "${aws_subnet.test.id}"
}

resource "aws_vpc" "foo" {
resource "aws_vpc" "test" {
cidr_block = "10.0.0.0/16"

tags = {
Name = "terraform-testacc-efs-mount-target"
Name = "tf-acc-efs-mount-target-test"
}
}

resource "aws_subnet" "alpha" {
vpc_id = "${aws_vpc.foo.id}"
availability_zone = "us-west-2a"
resource "aws_subnet" "test" {
vpc_id = "${aws_vpc.test.id}"
availability_zone = "${data.aws_availability_zones.available.names[0]}"
cidr_block = "10.0.1.0/24"

tags = {
Name = "tf-acc-efs-mount-target"
Name = "tf-acc-efs-mount-target-test"
}
}

data "aws_efs_mount_target" "by_mount_target_id" {
mount_target_id = "${aws_efs_mount_target.alpha.id}"
data "aws_efs_mount_target" "test" {
mount_target_id = "${aws_efs_mount_target.test.id}"
}
`, ct)
}
79 changes: 43 additions & 36 deletions aws/resource_aws_efs_mount_target.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import (

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/efs"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
)

func resourceAwsEfsMountTarget() *schema.Resource {
Expand All @@ -37,16 +37,16 @@ func resourceAwsEfsMountTarget() *schema.Resource {
},

"ip_address": {
Type: schema.TypeString,
Computed: true,
Optional: true,
ForceNew: true,
Type: schema.TypeString,
Computed: true,
Optional: true,
ForceNew: true,
ValidateFunc: validation.IsIPv4Address,
},

"security_groups": {
Type: schema.TypeSet,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
Computed: true,
Optional: true,
},
Expand All @@ -65,6 +65,22 @@ func resourceAwsEfsMountTarget() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"mount_target_dns_name": {
Type: schema.TypeString,
Computed: true,
},
"availability_zone_name": {
Type: schema.TypeString,
Computed: true,
},
"availability_zone_id": {
Type: schema.TypeString,
Computed: true,
},
"owner_id": {
Type: schema.TypeString,
Computed: true,
},
},
}
}
Expand Down Expand Up @@ -96,7 +112,7 @@ func resourceAwsEfsMountTargetCreate(d *schema.ResourceData, meta interface{}) e
input.IpAddress = aws.String(v.(string))
}
if v, ok := d.GetOk("security_groups"); ok {
input.SecurityGroups = expandStringList(v.(*schema.Set).List())
input.SecurityGroups = expandStringSet(v.(*schema.Set))
}

log.Printf("[DEBUG] Creating EFS mount target: %#v", input)
Expand All @@ -106,12 +122,12 @@ func resourceAwsEfsMountTargetCreate(d *schema.ResourceData, meta interface{}) e
return err
}

d.SetId(*mt.MountTargetId)
d.SetId(aws.StringValue(mt.MountTargetId))
log.Printf("[INFO] EFS mount target ID: %s", d.Id())

stateConf := &resource.StateChangeConf{
Pending: []string{"creating"},
Target: []string{"available"},
Pending: []string{efs.LifeCycleStateCreating},
Target: []string{efs.LifeCycleStateAvailable},
Refresh: func() (interface{}, string, error) {
resp, err := conn.DescribeMountTargets(&efs.DescribeMountTargetsInput{
MountTargetId: aws.String(d.Id()),
Expand All @@ -126,8 +142,8 @@ func resourceAwsEfsMountTargetCreate(d *schema.ResourceData, meta interface{}) e

mt := resp.MountTargets[0]

log.Printf("[DEBUG] Current status of %q: %q", *mt.MountTargetId, *mt.LifeCycleState)
return mt, *mt.LifeCycleState, nil
log.Printf("[DEBUG] Current status of %q: %q", aws.StringValue(mt.MountTargetId), aws.StringValue(mt.LifeCycleState))
return mt, aws.StringValue(mt.LifeCycleState), nil
},
Timeout: 10 * time.Minute,
Delay: 2 * time.Second,
Expand All @@ -136,10 +152,10 @@ func resourceAwsEfsMountTargetCreate(d *schema.ResourceData, meta interface{}) e

_, err = stateConf.WaitForState()
if err != nil {
return fmt.Errorf("Error waiting for EFS mount target (%s) to create: %s", d.Id(), err)
return fmt.Errorf("error waiting for EFS mount target (%s) to create: %s", d.Id(), err)
}

log.Printf("[DEBUG] EFS mount target created: %s", *mt.MountTargetId)
log.Printf("[DEBUG] EFS mount target created: %s", aws.StringValue(mt.MountTargetId))

return resourceAwsEfsMountTargetRead(d, meta)
}
Expand All @@ -150,7 +166,7 @@ func resourceAwsEfsMountTargetUpdate(d *schema.ResourceData, meta interface{}) e
if d.HasChange("security_groups") {
input := efs.ModifyMountTargetSecurityGroupsInput{
MountTargetId: aws.String(d.Id()),
SecurityGroups: expandStringList(d.Get("security_groups").(*schema.Set).List()),
SecurityGroups: expandStringSet(d.Get("security_groups").(*schema.Set)),
}
_, err := conn.ModifyMountTargetSecurityGroups(&input)
if err != nil {
Expand All @@ -167,7 +183,7 @@ func resourceAwsEfsMountTargetRead(d *schema.ResourceData, meta interface{}) err
MountTargetId: aws.String(d.Id()),
})
if err != nil {
if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "MountTargetNotFound" {
if isAWSErr(err, efs.ErrCodeMountTargetNotFound, "") {
// The EFS mount target could not be found,
// which would indicate that it might be
// already deleted.
Expand All @@ -186,8 +202,6 @@ func resourceAwsEfsMountTargetRead(d *schema.ResourceData, meta interface{}) err

log.Printf("[DEBUG] Found EFS mount target: %#v", mt)

d.SetId(*mt.MountTargetId)

fsARN := arn.ARN{
AccountID: meta.(*AWSClient).accountid,
Partition: meta.(*AWSClient).partition,
Expand All @@ -201,6 +215,9 @@ func resourceAwsEfsMountTargetRead(d *schema.ResourceData, meta interface{}) err
d.Set("ip_address", mt.IpAddress)
d.Set("subnet_id", mt.SubnetId)
d.Set("network_interface_id", mt.NetworkInterfaceId)
d.Set("availability_zone_name", mt.AvailabilityZoneName)
d.Set("availability_zone_id", mt.AvailabilityZoneId)
d.Set("owner_id", mt.OwnerId)

sgResp, err := conn.DescribeMountTargetSecurityGroups(&efs.DescribeMountTargetSecurityGroupsInput{
MountTargetId: aws.String(d.Id()),
Expand All @@ -209,18 +226,13 @@ func resourceAwsEfsMountTargetRead(d *schema.ResourceData, meta interface{}) err
return err
}

err = d.Set("security_groups", schema.NewSet(schema.HashString, flattenStringList(sgResp.SecurityGroups)))
err = d.Set("security_groups", flattenStringSet(sgResp.SecurityGroups))
if err != nil {
return err
}

// DNS name per http://docs.aws.amazon.com/efs/latest/ug/mounting-fs-mount-cmd-dns-name.html
_, err = getAzFromSubnetId(*mt.SubnetId, meta.(*AWSClient).ec2conn)
if err != nil {
return fmt.Errorf("Failed getting Availability Zone from subnet ID (%s): %s", *mt.SubnetId, err)
}

d.Set("dns_name", meta.(*AWSClient).RegionalHostname(fmt.Sprintf("%s.efs", aws.StringValue(mt.FileSystemId))))
d.Set("mount_target_dns_name", meta.(*AWSClient).RegionalHostname(fmt.Sprintf("%s.%s.efs", aws.StringValue(mt.AvailabilityZoneName), aws.StringValue(mt.FileSystemId))))

return nil
}
Expand All @@ -238,7 +250,7 @@ func getAzFromSubnetId(subnetId string, conn *ec2.EC2) (string, error) {
return "", fmt.Errorf("Expected exactly 1 subnet returned for %q, got: %d", subnetId, l)
}

return *out.Subnets[0].AvailabilityZone, nil
return aws.StringValue(out.Subnets[0].AvailabilityZone), nil
}

func resourceAwsEfsMountTargetDelete(d *schema.ResourceData, meta interface{}) error {
Expand All @@ -264,23 +276,18 @@ func resourceAwsEfsMountTargetDelete(d *schema.ResourceData, meta interface{}) e

func waitForDeleteEfsMountTarget(conn *efs.EFS, id string, timeout time.Duration) error {
stateConf := &resource.StateChangeConf{
Pending: []string{"available", "deleting", "deleted"},
Pending: []string{efs.LifeCycleStateAvailable, efs.LifeCycleStateDeleting, efs.LifeCycleStateDeleted},
Target: []string{},
Refresh: func() (interface{}, string, error) {
resp, err := conn.DescribeMountTargets(&efs.DescribeMountTargetsInput{
MountTargetId: aws.String(id),
})
if err != nil {
awsErr, ok := err.(awserr.Error)
if !ok {
return nil, "error", err
}

if awsErr.Code() == "MountTargetNotFound" {
if isAWSErr(err, efs.ErrCodeMountTargetNotFound, "") {
return nil, "", nil
}

return nil, "error", awsErr
return nil, "error", err
}

if hasEmptyMountTargets(resp) {
Expand All @@ -289,8 +296,8 @@ func waitForDeleteEfsMountTarget(conn *efs.EFS, id string, timeout time.Duration

mt := resp.MountTargets[0]

log.Printf("[DEBUG] Current status of %q: %q", *mt.MountTargetId, *mt.LifeCycleState)
return mt, *mt.LifeCycleState, nil
log.Printf("[DEBUG] Current status of %q: %q", aws.StringValue(mt.MountTargetId), aws.StringValue(mt.LifeCycleState))
return mt, aws.StringValue(mt.LifeCycleState), nil
},
Timeout: timeout,
Delay: 2 * time.Second,
Expand Down