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

Supporting EIPs with specified BYOIP addresses #8876

Merged
merged 10 commits into from
Apr 28, 2021
76 changes: 37 additions & 39 deletions aws/resource_aws_eip.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,96 +41,86 @@ func resourceAwsEip() *schema.Resource {
},

Schema: map[string]*schema.Schema{
"vpc": {
Type: schema.TypeBool,
"address": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Computed: true,
},

"instance": {
"allocation_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},

"network_interface": {
"associate_with_private_ip": {
Type: schema.TypeString,
Optional: true,
},
"association_id": {
Type: schema.TypeString,
Computed: true,
},

"allocation_id": {
"carrier_ip": {
Type: schema.TypeString,
Computed: true,
},

"association_id": {
"customer_owned_ip": {
Type: schema.TypeString,
Computed: true,
},

"customer_owned_ipv4_pool": {
Type: schema.TypeString,
Optional: true,
},
"domain": {
Type: schema.TypeString,
Computed: true,
},

"public_ip": {
"instance": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},

"public_dns": {
"network_border_group": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},

"private_ip": {
"network_interface": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},

"private_dns": {
Type: schema.TypeString,
Computed: true,
},

"associate_with_private_ip": {
Type: schema.TypeString,
Optional: true,
},

"carrier_ip": {
"private_ip": {
Type: schema.TypeString,
Computed: true,
},

"customer_owned_ipv4_pool": {
"public_dns": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},

"customer_owned_ip": {
"public_ip": {
Type: schema.TypeString,
Computed: true,
},

"public_ipv4_pool": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Computed: true,
},

"network_border_group": {
Type: schema.TypeString,
"tags": tagsSchema(),
"tags_all": tagsSchemaComputed(),
"vpc": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
ForceNew: true,
Computed: true,
},

"tags": tagsSchema(),
"tags_all": tagsSchemaComputed(),
},
}
}
Expand Down Expand Up @@ -158,6 +148,14 @@ func resourceAwsEipCreate(d *schema.ResourceData, meta interface{}) error {
allocOpts.TagSpecifications = ec2TagSpecificationsFromKeyValueTags(tags, ec2.ResourceTypeElasticIp)
}

if v, ok := d.GetOk("address"); ok {
supportedPlatforms := meta.(*AWSClient).supportedplatforms
if domainOpt != ec2.DomainTypeVpc && len(supportedPlatforms) > 0 && hasEc2Classic(supportedPlatforms) {
return fmt.Errorf("error, address to recover cannot be set for a standard-domain EIP - must be a VPC-domain EIP")
}
allocOpts.Address = aws.String(v.(string))
}

if v, ok := d.GetOk("public_ipv4_pool"); ok {
allocOpts.PublicIpv4Pool = aws.String(v.(string))
}
Expand Down
119 changes: 117 additions & 2 deletions aws/resource_aws_eip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func TestAccAWSEIP_Instance(t *testing.T) {
CheckDestroy: testAccCheckAWSEIPDestroy,
Steps: []resource.TestStep{
{
Config: testAccEIPInstanceConfig(),
Config: testAccAWSEIPInstanceConfig(),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEIPExists(resourceName, false, &conf),
testAccCheckAWSEIPAttributes(&conf),
Expand Down Expand Up @@ -660,6 +660,96 @@ func TestAccAWSEIP_carrierIP(t *testing.T) {
})
}

func TestAccAWSEIP_BYOIPAddress_default(t *testing.T) {
// Test case address not set
var conf ec2.Address
resourceName := "aws_eip.bar"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID),
IDRefreshName: resourceName,
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEIPDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSEIPConfig_BYOIPAddress_custom_default,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEIPExists(resourceName, false, &conf),
testAccCheckAWSEIPAttributes(&conf),
),
},
},
})
}

func TestAccAWSEIP_BYOIPAddress_custom(t *testing.T) {
// Test Case for address being set

if os.Getenv("AWS_EC2_EIP_BYOIP_ADDRESS") == "" {
t.Skip("Environment variable AWS_EC2_EIP_BYOIP_ADDRESS is not set")
}

var conf ec2.Address
resourceName := "aws_eip.bar"

address := os.Getenv("AWS_EC2_EIP_BYOIP_ADDRESS")

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID),
IDRefreshName: resourceName,
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEIPDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSEIPConfig_BYOIPAddress_custom(address),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEIPExists(resourceName, false, &conf),
testAccCheckAWSEIPAttributes(&conf),
resource.TestCheckResourceAttr(resourceName, "public_ip", address),
),
},
},
})
}

func TestAccAWSEIP_BYOIPAddress_custom_with_PublicIpv4Pool(t *testing.T) {
// Test Case for both address and public_ipv4_pool being set
if os.Getenv("AWS_EC2_EIP_BYOIP_ADDRESS") == "" {
t.Skip("Environment variable AWS_EC2_EIP_BYOIP_ADDRESS is not set")
}

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"

address := os.Getenv("AWS_EC2_EIP_BYOIP_ADDRESS")
poolName := os.Getenv("AWS_EC2_EIP_PUBLIC_IPV4_POOL")

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, ec2.EndpointsID),
IDRefreshName: resourceName,
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSEIPDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSEIPConfig_BYOIPAddress_custom_with_PublicIpv4Pool(address, poolName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEIPExists(resourceName, false, &conf),
testAccCheckAWSEIPAttributes(&conf),
resource.TestCheckResourceAttr(resourceName, "public_ip", address),
resource.TestCheckResourceAttr(resourceName, "public_ipv4_pool", poolName),
),
},
},
})
}

func testAccCheckAWSEIPDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).ec2conn

Expand Down Expand Up @@ -929,7 +1019,32 @@ resource "aws_eip" "test" {
`)
}

func testAccEIPInstanceConfig() string {
const testAccAWSEIPConfig_BYOIPAddress_custom_default = `
resource "aws_eip" "bar" {
vpc = true
}
`

func testAccAWSEIPConfig_BYOIPAddress_custom(address string) string {
return fmt.Sprintf(`
resource "aws_eip" "bar" {
vpc = true
address = %[1]q
}
`, address)
}

func testAccAWSEIPConfig_BYOIPAddress_custom_with_PublicIpv4Pool(address string, poolname string) string {
return fmt.Sprintf(`
resource "aws_eip" "bar" {
vpc = true
address = %[1]q
public_ipv4_pool = %[2]q
}
`, address, poolname)
}

func testAccAWSEIPInstanceConfig() string {
return composeConfig(
testAccLatestAmazonLinuxHvmEbsAmiConfig(),
testAccAvailableEc2InstanceTypeForAvailabilityZone("aws_subnet.test.availability_zone", "t3.micro", "t2.micro"),
Expand Down
6 changes: 6 additions & 0 deletions website/docs/r/eip.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,23 @@ resource "aws_eip" "byoip-ip" {

The following arguments are supported:

* `address` - (Optional) IP address from an EC2 BYOIP pool. This option is only available for VPC EIPs.
* `associate_with_private_ip` - (Optional) User-specified primary or secondary private IP address to 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.
* `customer_owned_ipv4_pool` - (Optional) ID of a customer-owned address pool. For more on customer owned IP addressed check out [Customer-owned IP addresses guide](https://docs.aws.amazon.com/outposts/latest/userguide/outposts-networking-components.html#ip-addressing).
* `customer_owned_ipv4_pool` - The ID of a customer-owned address pool. For more on customer owned IP addressed check out [Customer-owned IP addresses guide](https://docs.aws.amazon.com/outposts/latest/userguide/outposts-networking-components.html#ip-addressing)
* `instance` - (Optional) EC2 instance ID.
* `network_border_group` - (Optional) Location from which the IP address is advertised. Use this parameter to limit the address to this location.
* `network_border_group` - The location from which the IP address is advertised. Use this parameter to limit the address to this location.
* `network_interface` - (Optional) Network interface ID to associate with.
* `public_ipv4_pool` - (Optional) EC2 IPv4 address pool identifier or `amazon`. This option is only available for VPC EIPs.
* `tags` - (Optional) Map of tags to assign to the resource. Tags can only be applied to EIPs in a VPC. If configured with a provider [`default_tags` configuration block](https://www.terraform.io/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level.
* `vpc` - (Optional) Boolean if the EIP is in a VPC or not.

~> **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 have undefined behavior. See the relevant [AssociateAddress API Call][1] for more information.

~> **NOTE:** Specifying both `public_ipv4_pool` and `address` won't cause an error but `address` will be used in the
case both options are defined as the api only requires one or the other.

## Attributes Reference

In addition to all arguments above, the following attributes are exported:
Expand Down