diff --git a/aws/data_source_aws_eip.go b/aws/data_source_aws_eip.go index 9b25d16701f..fe650108b1d 100644 --- a/aws/data_source_aws_eip.go +++ b/aws/data_source_aws_eip.go @@ -14,17 +14,45 @@ func dataSourceAwsEip() *schema.Resource { Read: dataSourceAwsEipRead, Schema: map[string]*schema.Schema{ + "association_id": { + Type: schema.TypeString, + Computed: true, + }, + "domain": { + Type: schema.TypeString, + Computed: true, + }, "filter": ec2CustomFiltersSchema(), "id": { Type: schema.TypeString, Optional: true, Computed: true, }, + "instance_id": { + Type: schema.TypeString, + Computed: true, + }, + "network_interface_id": { + Type: schema.TypeString, + Computed: true, + }, + "network_interface_owner_id": { + Type: schema.TypeString, + Computed: true, + }, + "private_ip": { + Type: schema.TypeString, + Computed: true, + }, "public_ip": { Type: schema.TypeString, Optional: true, Computed: true, }, + "public_ipv4_pool": { + Type: schema.TypeString, + Computed: true, + }, "tags": tagsSchemaComputed(), }, } @@ -79,7 +107,14 @@ func dataSourceAwsEipRead(d *schema.ResourceData, meta interface{}) error { d.SetId(aws.StringValue(eip.PublicIp)) } + d.Set("association_id", eip.AssociationId) + d.Set("domain", eip.Domain) + d.Set("instance_id", eip.InstanceId) + d.Set("network_interface_id", eip.NetworkInterfaceId) + d.Set("network_interface_owner_id", eip.NetworkInterfaceOwnerId) + d.Set("private_ip", eip.PrivateIpAddress) d.Set("public_ip", eip.PublicIp) + d.Set("public_ipv4_pool", eip.PublicIpv4Pool) d.Set("tags", tagsToMap(eip.Tags)) return nil diff --git a/aws/data_source_aws_eip_test.go b/aws/data_source_aws_eip_test.go index b6703ac5ad7..e771b9cedb5 100644 --- a/aws/data_source_aws_eip_test.go +++ b/aws/data_source_aws_eip_test.go @@ -81,6 +81,7 @@ func TestAccDataSourceAwsEip_PublicIP_VPC(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrPair(dataSourceName, "id", resourceName, "id"), resource.TestCheckResourceAttrPair(dataSourceName, "public_ip", resourceName, "public_ip"), + resource.TestCheckResourceAttrPair(dataSourceName, "domain", resourceName, "domain"), ), }, }, @@ -107,6 +108,47 @@ func TestAccDataSourceAwsEip_Tags(t *testing.T) { }) } +func TestAccDataSourceAwsEip_NetworkInterface(t *testing.T) { + dataSourceName := "data.aws_eip.test" + resourceName := "aws_eip.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsEipConfigNetworkInterface, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "id", resourceName, "id"), + resource.TestCheckResourceAttrPair(dataSourceName, "network_interface_id", resourceName, "network_interface"), + resource.TestCheckResourceAttrPair(dataSourceName, "private_ip", resourceName, "private_ip"), + resource.TestCheckResourceAttrPair(dataSourceName, "domain", resourceName, "domain"), + ), + }, + }, + }) +} + +func TestAccDataSourceAwsEip_Instance(t *testing.T) { + dataSourceName := "data.aws_eip.test" + resourceName := "aws_eip.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsEipConfigInstance, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "id", resourceName, "id"), + resource.TestCheckResourceAttrPair(dataSourceName, "instance_id", resourceName, "instance"), + resource.TestCheckResourceAttrPair(dataSourceName, "association_id", resourceName, "association_id"), + ), + }, + }, + }) +} + func testAccDataSourceAwsEipConfigFilter(rName string) string { return fmt.Sprintf(` resource "aws_eip" "test" { @@ -175,3 +217,76 @@ data "aws_eip" "test" { } `, rName) } + +const testAccDataSourceAwsEipConfigNetworkInterface = ` +resource "aws_vpc" "test" { + cidr_block = "10.1.0.0/16" +} + +resource "aws_subnet" "test" { + vpc_id = "${aws_vpc.test.id}" + cidr_block = "10.1.0.0/24" +} + +resource "aws_internet_gateway" "test" { + vpc_id = "${aws_vpc.test.id}" +} + +resource "aws_network_interface" "test" { + subnet_id = "${aws_subnet.test.id}" +} + +resource "aws_eip" "test" { + vpc = true + network_interface = "${aws_network_interface.test.id}" +} + +data "aws_eip" "test" { + filter { + name = "network-interface-id" + values = ["${aws_eip.test.network_interface}"] + } +} +` + +const testAccDataSourceAwsEipConfigInstance = ` +resource "aws_vpc" "test" { + cidr_block = "10.2.0.0/16" +} + +resource "aws_subnet" "test" { + vpc_id = "${aws_vpc.test.id}" + cidr_block = "10.2.0.0/24" +} + +resource "aws_internet_gateway" "test" { + vpc_id = "${aws_vpc.test.id}" +} + +data "aws_ami" "test" { + most_recent = true + name_regex = "^amzn-ami.*ecs-optimized$" + + owners = [ + "amazon", + ] +} + +resource "aws_instance" "test" { + ami = "${data.aws_ami.test.id}" + subnet_id = "${aws_subnet.test.id}" + instance_type = "t2.micro" +} + +resource "aws_eip" "test" { + vpc = true + instance = "${aws_instance.test.id}" +} + +data "aws_eip" "test" { + filter { + name = "instance-id" + values = ["${aws_eip.test.instance}"] + } +} +` diff --git a/aws/resource_aws_eip.go b/aws/resource_aws_eip.go index 16833166dfa..c3f8a1d580c 100644 --- a/aws/resource_aws_eip.go +++ b/aws/resource_aws_eip.go @@ -80,6 +80,13 @@ func resourceAwsEip() *schema.Resource { Optional: true, }, + "public_ipv4_pool": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + }, + "tags": tagsSchema(), }, } @@ -98,6 +105,10 @@ func resourceAwsEipCreate(d *schema.ResourceData, meta interface{}) error { Domain: aws.String(domainOpt), } + if v, ok := d.GetOk("public_ipv4_pool"); ok { + allocOpts.PublicIpv4Pool = aws.String(v.(string)) + } + log.Printf("[DEBUG] EIP create configuration: %#v", allocOpts) allocResp, err := ec2conn.AllocateAddress(allocOpts) if err != nil { @@ -211,6 +222,7 @@ func resourceAwsEipRead(d *schema.ResourceData, meta interface{}) error { } d.Set("private_ip", address.PrivateIpAddress) d.Set("public_ip", address.PublicIp) + d.Set("public_ipv4_pool", address.PublicIpv4Pool) // On import (domain never set, which it must've been if we created), // set the 'vpc' attribute depending on if we're in a VPC. diff --git a/aws/resource_aws_eip_test.go b/aws/resource_aws_eip_test.go index 6bb7b21988d..76c4229f263 100644 --- a/aws/resource_aws_eip_test.go +++ b/aws/resource_aws_eip_test.go @@ -306,6 +306,56 @@ func TestAccAWSEIP_tags(t *testing.T) { }) } +func TestAccAWSEIP_PublicIpv4Pool_default(t *testing.T) { + var conf ec2.Address + resourceName := "aws_eip.bar" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: resourceName, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEIPDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEIPConfig_PublicIpv4Pool_default, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEIPExists(resourceName, &conf), + testAccCheckAWSEIPAttributes(&conf), + resource.TestCheckResourceAttr(resourceName, "public_ipv4_pool", "amazon"), + ), + }, + }, + }) +} + +func TestAccAWSEIP_PublicIpv4Pool_custom(t *testing.T) { + if os.Getenv("AWS_EC2_EIP_PUBLIC_IPV4_POOL") == "" { + t.Skip("Environment variable AWS_EC2_EIP_PUBLIC_IPV4_POOL is not set") + } + + var conf ec2.Address + resourceName := "aws_eip.bar" + + poolName := fmt.Sprintf("%s", os.Getenv("AWS_EC2_EIP_PUBLIC_IPV4_POOL")) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: resourceName, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEIPDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEIPConfig_PublicIpv4Pool_custom(poolName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEIPExists(resourceName, &conf), + testAccCheckAWSEIPAttributes(&conf), + resource.TestCheckResourceAttr(resourceName, "public_ipv4_pool", poolName), + ), + }, + }, + }) +} + func testAccCheckAWSEIPDisappears(v *ec2.Address) resource.TestCheckFunc { return func(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).ec2conn @@ -454,6 +504,21 @@ resource "aws_eip" "bar" { `, rName, testName) } +const testAccAWSEIPConfig_PublicIpv4Pool_default = ` +resource "aws_eip" "bar" { + vpc = true +} +` + +func testAccAWSEIPConfig_PublicIpv4Pool_custom(poolName string) string { + return fmt.Sprintf(` +resource "aws_eip" "bar" { + vpc = true + public_ipv4_pool = "%s" +} +`, poolName) +} + const testAccAWSEIPInstanceEc2Classic = ` provider "aws" { region = "us-east-1" @@ -716,7 +781,7 @@ resource "aws_subnet" "bar" { availability_zone = "us-west-2a" cidr_block = "10.0.0.0/24" tags { - Name = "tf-acc-eip-network-interface" + Name = "tf-acc-eip-network-interface" } } @@ -750,7 +815,7 @@ resource "aws_subnet" "bar" { availability_zone = "us-west-2a" cidr_block = "10.0.0.0/24" tags { - Name = "tf-acc-eip-multi-network-interface" + Name = "tf-acc-eip-multi-network-interface" } } diff --git a/website/docs/d/eip.html.markdown b/website/docs/d/eip.html.markdown index 26efdf43446..fffd6fb4646 100644 --- a/website/docs/d/eip.html.markdown +++ b/website/docs/d/eip.html.markdown @@ -64,6 +64,13 @@ Elastic IP whose data will be exported as attributes. In addition to all arguments above, the following attributes are exported: +* `association_id` - The ID representing the association of the address with an instance in a VPC. +* `domain` - Indicates whether the address is for use in EC2-Classic (standard) or in a VPC (vpc). * `id` - If VPC Elastic IP, the allocation identifier. If EC2-Classic Elastic IP, the public IP address. +* `instance_id` - The ID of the instance that the address is associated with (if any). +* `network_interface_id` - The ID of the network interface. +* `network_interface_owner_id` - The ID of the AWS account that owns the network interface. +* `private_ip` - The private IP address associated with the Elastic IP address. * `public_ip` - Public IP address of Elastic IP. +* `public_ipv4_pool` - The ID of an address pool. * `tags` - Key-value map of tags associated with Elastic IP. diff --git a/website/docs/r/eip.html.markdown b/website/docs/r/eip.html.markdown index 31c1215abd5..d15fc35557f 100644 --- a/website/docs/r/eip.html.markdown +++ b/website/docs/r/eip.html.markdown @@ -84,6 +84,15 @@ resource "aws_eip" "bar" { } ``` +Allocating EIP from the BYOIP pool: + +```hcl +resource "aws_eip" "byoip-ip" { + vpc = true + public_ipv4_pool = "ipv4pool-ec2-012345" +} +``` + ## Argument Reference The following arguments are supported: @@ -95,6 +104,7 @@ The following arguments are supported: associate with the Elastic IP address. If no private IP address is specified, the Elastic IP address is associated with the primary private IP address. * `tags` - (Optional) A mapping of tags to assign to the resource. +* `public_ipv4_pool` - (Optional) EC2 IPv4 address pool identifier or `amazon`. This option is only available for VPC EIPs. ~> **NOTE:** You can specify either the `instance` ID or the `network_interface` ID, but not both. Including both will **not** return an error from the AWS API, but will @@ -112,6 +122,7 @@ In addition to all arguments above, the following attributes are exported: * `public_ip` - Contains the public IP address. * `instance` - Contains the ID of the attached instance. * `network_interface` - Contains the ID of the attached network interface. +* `public_ipv4_pool` - EC2 IPv4 address pool identifier (if in VPC). ## Timeouts `aws_eip` provides the following [Timeouts](/docs/configuration/resources.html#timeouts) configuration options: