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

provider/aws: allow assocation of EIP to ENI #1681

Merged
merged 3 commits into from
May 5, 2015
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
45 changes: 26 additions & 19 deletions builtin/providers/aws/resource_aws_eip.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -102,22 +108,18 @@ func resourceAwsEipRead(d *schema.ResourceData, meta interface{}) error {
domain := resourceAwsEipDomain(d)
id := d.Id()

var assocIds []*string
var publicIps []*string
req := &ec2.DescribeAddressesInput{}

if domain == "vpc" {
assocIds = []*string{aws.String(id)}
req.AllocationIDs = []*string{aws.String(id)}
} else {
publicIps = []*string{aws.String(id)}
req.PublicIPs = []*string{aws.String(id)}
}

log.Printf(
"[DEBUG] EIP describe configuration: %#v, %#v (domain: %s)",
assocIds, publicIps, domain)
"[DEBUG] EIP describe configuration: %#v (domain: %s)",
req, domain)

req := &ec2.DescribeAddressesInput{
AllocationIDs: assocIds,
PublicIPs: publicIps,
}
describeAddresses, err := ec2conn.DescribeAddresses(req)
if err != nil {
if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidAllocationID.NotFound" {
Expand All @@ -141,6 +143,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)

Expand All @@ -152,9 +155,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),
Expand All @@ -164,16 +171,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)
}
}

Expand All @@ -191,8 +198,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) {
Expand Down
52 changes: 52 additions & 0 deletions builtin/providers/aws/resource_aws_eip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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}"
}
`