From b29e9d3b6feda7ad523935d682e0733dea0e474c Mon Sep 17 00:00:00 2001 From: James Stremick Date: Sat, 25 Apr 2015 22:30:37 -0400 Subject: [PATCH 1/3] Allow assocation of EIP to ENI --- builtin/providers/aws/resource_aws_eip.go | 39 +++++++++----- .../providers/aws/resource_aws_eip_test.go | 52 +++++++++++++++++++ 2 files changed, 79 insertions(+), 12 deletions(-) diff --git a/builtin/providers/aws/resource_aws_eip.go b/builtin/providers/aws/resource_aws_eip.go index f871e764d..b667b0779 100644 --- a/builtin/providers/aws/resource_aws_eip.go +++ b/builtin/providers/aws/resource_aws_eip.go @@ -31,6 +31,12 @@ func resourceAwsEip() *schema.Resource { Optional: true, }, + "network_interface": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"instance"}, + }, + "allocation_id": &schema.Schema{ Type: schema.TypeString, Computed: true, @@ -114,10 +120,14 @@ func resourceAwsEipRead(d *schema.ResourceData, meta interface{}) error { "[DEBUG] EIP describe configuration: %#v, %#v (domain: %s)", assocIds, publicIps, domain) - req := &ec2.DescribeAddressesInput{ - AllocationIDs: assocIds, - PublicIPs: publicIps, + req := &ec2.DescribeAddressesInput{} + + if domain == "vpc" { + req.AllocationIDs = []*string{aws.String(id)} + } else { + req.PublicIPs = []*string{aws.String(id)} } + describeAddresses, err := ec2conn.DescribeAddresses(req) if err != nil { if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidAllocationID.NotFound" { @@ -141,6 +151,7 @@ func resourceAwsEipRead(d *schema.ResourceData, meta interface{}) error { d.Set("association_id", address.AssociationID) d.Set("instance", address.InstanceID) + d.Set("network_interface", address.NetworkInterfaceID) d.Set("private_ip", address.PrivateIPAddress) d.Set("public_ip", address.PublicIP) @@ -152,9 +163,13 @@ func resourceAwsEipUpdate(d *schema.ResourceData, meta interface{}) error { domain := resourceAwsEipDomain(d) - // Only register with an instance if we have one - if v, ok := d.GetOk("instance"); ok { - instanceId := v.(string) + // Associate to instance or interface if specified + v_instance, ok_instance := d.GetOk("instance") + v_interface, ok_interface := d.GetOk("network_interface") + + if ok_instance || ok_interface { + instanceId := v_instance.(string) + networkInterfaceId := v_interface.(string) assocOpts := &ec2.AssociateAddressInput{ InstanceID: aws.String(instanceId), @@ -164,16 +179,16 @@ func resourceAwsEipUpdate(d *schema.ResourceData, meta interface{}) error { // more unique ID conditionals if domain == "vpc" { assocOpts = &ec2.AssociateAddressInput{ - InstanceID: aws.String(instanceId), - AllocationID: aws.String(d.Id()), - PublicIP: aws.String(""), + NetworkInterfaceID: aws.String(networkInterfaceId), + InstanceID: aws.String(instanceId), + AllocationID: aws.String(d.Id()), } } log.Printf("[DEBUG] EIP associate configuration: %#v (domain: %v)", assocOpts, domain) _, err := ec2conn.AssociateAddress(assocOpts) if err != nil { - return fmt.Errorf("Failure associating instances: %s", err) + return fmt.Errorf("Failure associating EIP: %s", err) } } @@ -191,8 +206,8 @@ func resourceAwsEipDelete(d *schema.ResourceData, meta interface{}) error { return nil } - // If we are attached to an instance, detach first. - if d.Get("instance").(string) != "" { + // If we are attached to an instance or interface, detach first. + if d.Get("instance").(string) != "" || d.Get("association_id").(string) != "" { log.Printf("[DEBUG] Disassociating EIP: %s", d.Id()) var err error switch resourceAwsEipDomain(d) { diff --git a/builtin/providers/aws/resource_aws_eip_test.go b/builtin/providers/aws/resource_aws_eip_test.go index 199dc3046..b87794131 100644 --- a/builtin/providers/aws/resource_aws_eip_test.go +++ b/builtin/providers/aws/resource_aws_eip_test.go @@ -57,6 +57,26 @@ func TestAccAWSEIP_instance(t *testing.T) { }) } +func TestAccAWSEIP_network_interface(t *testing.T) { + var conf ec2.Address + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEIPDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSEIPNetworkInterfaceConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEIPExists("aws_eip.bar", &conf), + testAccCheckAWSEIPAttributes(&conf), + testAccCheckAWSEIPAssociated(&conf), + ), + }, + }, + }) +} + func testAccCheckAWSEIPDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).ec2conn @@ -101,6 +121,16 @@ func testAccCheckAWSEIPAttributes(conf *ec2.Address) resource.TestCheckFunc { } } +func testAccCheckAWSEIPAssociated(conf *ec2.Address) resource.TestCheckFunc { + return func(s *terraform.State) error { + if *conf.AssociationID == "" { + return fmt.Errorf("empty association_id") + } + + return nil + } +} + func testAccCheckAWSEIPExists(n string, res *ec2.Address) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -177,3 +207,25 @@ resource "aws_eip" "bar" { instance = "${aws_instance.bar.id}" } ` +const testAccAWSEIPNetworkInterfaceConfig = ` +resource "aws_vpc" "bar" { + cidr_block = "10.0.0.0/24" +} +resource "aws_internet_gateway" "bar" { + vpc_id = "${aws_vpc.bar.id}" +} +resource "aws_subnet" "bar" { + vpc_id = "${aws_vpc.bar.id}" + availability_zone = "us-west-2a" + cidr_block = "10.0.0.0/24" +} +resource "aws_network_interface" "bar" { + subnet_id = "${aws_subnet.bar.id}" + private_ips = ["10.0.0.10"] + security_groups = [ "${aws_vpc.bar.default_security_group_id}" ] +} +resource "aws_eip" "bar" { + vpc = "true" + network_interface = "${aws_network_interface.bar.id}" +} +` From 244639cf3da56c1b3270f97b507b72d673093673 Mon Sep 17 00:00:00 2001 From: James Stremick Date: Mon, 27 Apr 2015 17:26:52 -0400 Subject: [PATCH 2/3] Remove some domain checking duplication --- builtin/providers/aws/resource_aws_eip.go | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/builtin/providers/aws/resource_aws_eip.go b/builtin/providers/aws/resource_aws_eip.go index b667b0779..8956ed507 100644 --- a/builtin/providers/aws/resource_aws_eip.go +++ b/builtin/providers/aws/resource_aws_eip.go @@ -108,18 +108,6 @@ func resourceAwsEipRead(d *schema.ResourceData, meta interface{}) error { domain := resourceAwsEipDomain(d) id := d.Id() - var assocIds []*string - var publicIps []*string - if domain == "vpc" { - assocIds = []*string{aws.String(id)} - } else { - publicIps = []*string{aws.String(id)} - } - - log.Printf( - "[DEBUG] EIP describe configuration: %#v, %#v (domain: %s)", - assocIds, publicIps, domain) - req := &ec2.DescribeAddressesInput{} if domain == "vpc" { @@ -128,9 +116,14 @@ func resourceAwsEipRead(d *schema.ResourceData, meta interface{}) error { req.PublicIPs = []*string{aws.String(id)} } + log.Printf( + "[DEBUG] EIP describe configuration: %#v (domain: %s)", + req, domain) + describeAddresses, err := ec2conn.DescribeAddresses(req) if err != nil { if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidAllocationID.NotFound" { + log.Printf("[DEBUG] EIP describe configuration: %#v", req) d.SetId("") return nil } From e586d05a7d8e55b94e70faea5a4f8cfbea5316ff Mon Sep 17 00:00:00 2001 From: James Stremick Date: Mon, 27 Apr 2015 17:30:47 -0400 Subject: [PATCH 3/3] Remove some unecessary debug output I added --- builtin/providers/aws/resource_aws_eip.go | 1 - 1 file changed, 1 deletion(-) diff --git a/builtin/providers/aws/resource_aws_eip.go b/builtin/providers/aws/resource_aws_eip.go index 8956ed507..4111780bb 100644 --- a/builtin/providers/aws/resource_aws_eip.go +++ b/builtin/providers/aws/resource_aws_eip.go @@ -123,7 +123,6 @@ func resourceAwsEipRead(d *schema.ResourceData, meta interface{}) error { describeAddresses, err := ec2conn.DescribeAddresses(req) if err != nil { if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidAllocationID.NotFound" { - log.Printf("[DEBUG] EIP describe configuration: %#v", req) d.SetId("") return nil }