provider/aws: Add efs_mount_target

This commit is contained in:
Radek Simko 2015-09-15 23:11:53 +01:00 committed by Radek Simko
parent cd96b8a7fc
commit 167b44770f
4 changed files with 371 additions and 1 deletions

View File

@ -176,6 +176,7 @@ func Provider() terraform.ResourceProvider {
"aws_ecs_service": resourceAwsEcsService(),
"aws_ecs_task_definition": resourceAwsEcsTaskDefinition(),
"aws_efs_file_system": resourceAwsEfsFileSystem(),
"aws_efs_mount_target": resourceAwsEfsMountTarget(),
"aws_eip": resourceAwsEip(),
"aws_elasticache_cluster": resourceAwsElasticacheCluster(),
"aws_elasticache_parameter_group": resourceAwsElasticacheParameterGroup(),

View File

@ -0,0 +1,223 @@
package aws
import (
"fmt"
"log"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/efs"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
)
func resourceAwsEfsMountTarget() *schema.Resource {
return &schema.Resource{
Create: resourceAwsEfsMountTargetCreate,
Read: resourceAwsEfsMountTargetRead,
Update: resourceAwsEfsMountTargetUpdate,
Delete: resourceAwsEfsMountTargetDelete,
Schema: map[string]*schema.Schema{
"file_system_id": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"ip_address": &schema.Schema{
Type: schema.TypeString,
Computed: true,
Optional: true,
ForceNew: true,
},
"security_groups": &schema.Schema{
Type: schema.TypeSet,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
Computed: true,
Optional: true,
},
"subnet_id": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"network_interface_id": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
},
}
}
func resourceAwsEfsMountTargetCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).efsconn
input := efs.CreateMountTargetInput{
FileSystemId: aws.String(d.Get("file_system_id").(string)),
SubnetId: aws.String(d.Get("subnet_id").(string)),
}
if v, ok := d.GetOk("ip_address"); ok {
input.IpAddress = aws.String(v.(string))
}
if v, ok := d.GetOk("security_groups"); ok {
input.SecurityGroups = expandStringList(v.(*schema.Set).List())
}
log.Printf("[DEBUG] Creating EFS mount target: %#v", input)
mt, err := conn.CreateMountTarget(&input)
if err != nil {
return err
}
d.SetId(*mt.MountTargetId)
stateConf := &resource.StateChangeConf{
Pending: []string{"creating"},
Target: "available",
Refresh: func() (interface{}, string, error) {
resp, err := conn.DescribeMountTargets(&efs.DescribeMountTargetsInput{
MountTargetId: aws.String(d.Id()),
})
if err != nil {
return nil, "error", err
}
if len(resp.MountTargets) < 1 {
return nil, "error", fmt.Errorf("EFS mount target %q not found", d.Id())
}
mt := resp.MountTargets[0]
log.Printf("[DEBUG] Current status of %q: %q", *mt.MountTargetId, *mt.LifeCycleState)
return mt, *mt.LifeCycleState, nil
},
Timeout: 10 * time.Minute,
Delay: 2 * time.Second,
MinTimeout: 3 * time.Second,
}
_, err = stateConf.WaitForState()
if err != nil {
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)
return resourceAwsEfsMountTargetRead(d, meta)
}
func resourceAwsEfsMountTargetUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).efsconn
if d.HasChange("security_groups") {
input := efs.ModifyMountTargetSecurityGroupsInput{
MountTargetId: aws.String(d.Id()),
SecurityGroups: expandStringList(d.Get("security_groups").(*schema.Set).List()),
}
_, err := conn.ModifyMountTargetSecurityGroups(&input)
if err != nil {
return err
}
}
return resourceAwsEfsMountTargetRead(d, meta)
}
func resourceAwsEfsMountTargetRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).efsconn
resp, err := conn.DescribeMountTargets(&efs.DescribeMountTargetsInput{
MountTargetId: aws.String(d.Id()),
})
if err != nil {
return err
}
if len(resp.MountTargets) < 1 {
return fmt.Errorf("EFS mount target %q not found", d.Id())
}
mt := resp.MountTargets[0]
log.Printf("[DEBUG] Found EFS mount target: %#v", mt)
d.SetId(*mt.MountTargetId)
d.Set("file_system_id", *mt.FileSystemId)
d.Set("ip_address", *mt.IpAddress)
d.Set("subnet_id", *mt.SubnetId)
d.Set("network_interface_id", *mt.NetworkInterfaceId)
sgResp, err := conn.DescribeMountTargetSecurityGroups(&efs.DescribeMountTargetSecurityGroupsInput{
MountTargetId: aws.String(d.Id()),
})
if err != nil {
return err
}
d.Set("security_groups", schema.NewSet(schema.HashString, flattenStringList(sgResp.SecurityGroups)))
return nil
}
func resourceAwsEfsMountTargetDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).efsconn
log.Printf("[DEBUG] Deleting EFS mount target %q", d.Id())
_, err := conn.DeleteMountTarget(&efs.DeleteMountTargetInput{
MountTargetId: aws.String(d.Id()),
})
if err != nil {
return err
}
stateConf := &resource.StateChangeConf{
Pending: []string{"available", "deleting", "deleted"},
Target: "",
Refresh: func() (interface{}, string, error) {
resp, err := conn.DescribeMountTargets(&efs.DescribeMountTargetsInput{
MountTargetId: aws.String(d.Id()),
})
if err != nil {
awsErr, ok := err.(awserr.Error)
if !ok {
return nil, "error", err
}
if awsErr.Code() == "MountTargetNotFound" {
return nil, "", nil
}
return nil, "error", awsErr
}
if len(resp.MountTargets) < 1 {
return nil, "", nil
}
mt := resp.MountTargets[0]
log.Printf("[DEBUG] Current status of %q: %q", *mt.MountTargetId, *mt.LifeCycleState)
return mt, *mt.LifeCycleState, nil
},
Timeout: 10 * time.Minute,
Delay: 2 * time.Second,
MinTimeout: 3 * time.Second,
}
_, err = stateConf.WaitForState()
if err != nil {
return fmt.Errorf("Error waiting for EFS mount target (%q) to delete: %q",
d.Id(), err.Error())
}
log.Printf("[DEBUG] EFS mount target %q deleted.", d.Id())
return nil
}

View File

@ -0,0 +1,135 @@
package aws
import (
"fmt"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/efs"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccAWSEFSMountTarget(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckEfsMountTargetDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAWSEFSMountTargetConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckEfsMountTarget(
"aws_efs_mount_target.alpha",
),
),
},
resource.TestStep{
Config: testAccAWSEFSMountTargetConfigModified,
Check: resource.ComposeTestCheckFunc(
testAccCheckEfsMountTarget(
"aws_efs_mount_target.alpha",
),
testAccCheckEfsMountTarget(
"aws_efs_mount_target.beta",
),
),
},
},
})
}
func testAccCheckEfsMountTargetDestroy(s *terraform.State) error {
if len(s.RootModule().Resources) > 0 {
return fmt.Errorf("Expected all resources to be gone, but found: %#v", s.RootModule().Resources)
}
return nil
}
func testAccCheckEfsMountTarget(resourceID string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[resourceID]
if !ok {
return fmt.Errorf("Not found: %s", resourceID)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}
fs, ok := s.RootModule().Resources[resourceID]
if !ok {
return fmt.Errorf("Not found: %s", resourceID)
}
conn := testAccProvider.Meta().(*AWSClient).efsconn
mt, err := conn.DescribeMountTargets(&efs.DescribeMountTargetsInput{
MountTargetId: aws.String(fs.Primary.ID),
})
if err != nil {
return err
}
if *mt.MountTargets[0].MountTargetId != fs.Primary.ID {
return fmt.Errorf("Mount target ID mismatch: %q != %q",
*mt.MountTargets[0].MountTargetId, fs.Primary.ID)
}
return nil
}
}
const testAccAWSEFSMountTargetConfig = `
resource "aws_efs_file_system" "foo" {
reference_name = "radeksimko"
}
resource "aws_efs_mount_target" "alpha" {
file_system_id = "${aws_efs_file_system.foo.id}"
subnet_id = "${aws_subnet.alpha.id}"
}
resource "aws_vpc" "foo" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "alpha" {
vpc_id = "${aws_vpc.foo.id}"
availability_zone = "us-west-2a"
cidr_block = "10.0.1.0/24"
}
`
const testAccAWSEFSMountTargetConfigModified = `
resource "aws_efs_file_system" "foo" {
reference_name = "radeksimko"
}
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" "beta" {
file_system_id = "${aws_efs_file_system.foo.id}"
subnet_id = "${aws_subnet.beta.id}"
}
resource "aws_vpc" "foo" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "alpha" {
vpc_id = "${aws_vpc.foo.id}"
availability_zone = "us-west-2a"
cidr_block = "10.0.1.0/24"
}
resource "aws_subnet" "beta" {
vpc_id = "${aws_vpc.foo.id}"
availability_zone = "us-west-2b"
cidr_block = "10.0.2.0/24"
}
`

View File

@ -368,7 +368,7 @@ func flattenElastiCacheParameters(list []*elasticache.Parameter) []map[string]in
}
// Takes the result of flatmap.Expand for an array of strings
// and returns a []string
// and returns a []*string
func expandStringList(configured []interface{}) []*string {
vs := make([]*string, 0, len(configured))
for _, v := range configured {
@ -377,6 +377,17 @@ func expandStringList(configured []interface{}) []*string {
return vs
}
// Takes list of pointers to strings. Expand to an array
// of raw strings and returns a []interface{}
// to keep compatibility w/ schema.NewSetschema.NewSet
func flattenStringList(list []*string) []interface{} {
vs := make([]interface{}, 0, len(list))
for _, v := range list {
vs = append(vs, *v)
}
return vs
}
//Flattens an array of private ip addresses into a []string, where the elements returned are the IP strings e.g. "192.168.0.0"
func flattenNetworkInterfacesPrivateIPAddresses(dtos []*ec2.NetworkInterfacePrivateIpAddress) []string {
ips := make([]string, 0, len(dtos))