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

Issues/1557 #9204

Closed
wants to merge 3 commits into from
Closed
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
65 changes: 51 additions & 14 deletions builtin/providers/aws/resource_aws_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ func resourceAwsInstance() *schema.Resource {
Computed: true,
},

"private_ip_addresses": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},

"source_dest_check": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Expand Down Expand Up @@ -493,6 +501,15 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
d.Set("private_dns", instance.PrivateDnsName)
d.Set("private_ip", instance.PrivateIpAddress)
d.Set("iam_instance_profile", iamInstanceProfileArnToName(instance.IamInstanceProfile))
// Possible future implementation ?
// get multiple private ip addresses if present
// if ips := instance.NetworkInterfaces[0].PrivateIpAddresses; len(ips) > 1 {
// for _, ip := range ips {
// //TODO
// }
// d.Set("private_ip_addresses", iplist)
// }
// d.Set("iam_instance_profile", iamInstanceProfileArnToName(instance.IamInstanceProfile))

if len(instance.NetworkInterfaces) > 0 {
for _, ni := range instance.NetworkInterfaces {
Expand Down Expand Up @@ -1067,6 +1084,37 @@ func buildAwsInstanceOpts(
}
}

// Always send the ENI with DeviceId 0 in the RunInstance request
// Reflect the PI structure and gives possibiity of extending all attributes
ni := &ec2.InstanceNetworkInterfaceSpecification{
AssociatePublicIpAddress: aws.Bool(associatePublicIPAddress),
DeviceIndex: aws.Int64(int64(0)),
SubnetId: aws.String(subnetID),
Groups: groups,
}

if v, ok := d.GetOk("private_ip"); ok {
ni.PrivateIpAddress = aws.String(v.(string))
}

if v, ok := d.GetOk("private_ip_addresses"); ok {
ni.PrivateIpAddresses = []*ec2.PrivateIpAddressSpecification{
&ec2.PrivateIpAddressSpecification{
Primary: aws.Bool(true),
PrivateIpAddress: ni.PrivateIpAddress,
},
}
// nil the PrivateIpAddress attr
ni.PrivateIpAddress = nil
// Assign PrivateIpAddresses attr
for _, ip := range v.(*schema.Set).List() {
ni.PrivateIpAddresses = append(ni.PrivateIpAddresses, &ec2.PrivateIpAddressSpecification{
Primary: aws.Bool(false),
PrivateIpAddress: aws.String(ip.(string)),
})
}
}

if hasSubnet && associatePublicIPAddress {
// If we have a non-default VPC / Subnet specified, we can flag
// AssociatePublicIpAddress to get a Public IP assigned. By default these are not provided.
Expand All @@ -1075,32 +1123,18 @@ func buildAwsInstanceOpts(
// You also need to attach Security Groups to the NetworkInterface instead of the instance,
// to avoid: Network interfaces and an instance-level security groups may not be specified on
// the same request
ni := &ec2.InstanceNetworkInterfaceSpecification{
AssociatePublicIpAddress: aws.Bool(associatePublicIPAddress),
DeviceIndex: aws.Int64(int64(0)),
SubnetId: aws.String(subnetID),
Groups: groups,
}

if v, ok := d.GetOk("private_ip"); ok {
ni.PrivateIpAddress = aws.String(v.(string))
}

if v := d.Get("vpc_security_group_ids").(*schema.Set); v.Len() > 0 {
for _, v := range v.List() {
ni.Groups = append(ni.Groups, aws.String(v.(string)))
}
}

opts.NetworkInterfaces = []*ec2.InstanceNetworkInterfaceSpecification{ni}
} else {
if subnetID != "" {
opts.SubnetID = aws.String(subnetID)
}

if v, ok := d.GetOk("private_ip"); ok {
opts.PrivateIPAddress = aws.String(v.(string))
}
if opts.SubnetID != nil &&
*opts.SubnetID != "" {
opts.SecurityGroupIDs = groups
Expand All @@ -1115,6 +1149,9 @@ func buildAwsInstanceOpts(
}
}

// Set the ENI
opts.NetworkInterfaces = []*ec2.InstanceNetworkInterfaceSpecification{ni}

if v, ok := d.GetOk("key_name"); ok {
opts.KeyName = aws.String(v.(string))
}
Expand Down
54 changes: 54 additions & 0 deletions builtin/providers/aws/resource_aws_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,41 @@ func TestAccAWSInstance_privateIP(t *testing.T) {
})
}

func TestAccAWSInstance_multiplePrivateIPs(t *testing.T) {
var v ec2.Instance

testCheckMultiplePrivateIPs := func() resource.TestCheckFunc {
return func(*terraform.State) error {
if *v.PrivateIpAddress != "10.1.1.42" {
return fmt.Errorf("bad private IP: %s", *v.PrivateIpAddress)
}
if *v.NetworkInterfaces[0].PrivateIpAddresses[0].PrivateIpAddress != "10.1.1.42" {
return fmt.Errorf("bad private primary IP: %s", *v.NetworkInterfaces[0].PrivateIpAddresses[0].PrivateIpAddress)
}
if *v.NetworkInterfaces[0].PrivateIpAddresses[2].PrivateIpAddress != "10.1.1.44" {
return fmt.Errorf("bad private ternany IP: %s", *v.NetworkInterfaces[0].PrivateIpAddresses[2].PrivateIpAddress)
}
return nil
}
}

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
IDRefreshName: "aws_instance.foo",
Providers: testAccProviders,
CheckDestroy: testAccCheckInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccInstanceConfigMultiplePrivateIPs,
Check: resource.ComposeTestCheckFunc(
testAccCheckInstanceExists("aws_instance.foo", &v),
testCheckMultiplePrivateIPs(),
),
},
},
})
}

func TestAccAWSInstance_associatePublicIPAndPrivateIP(t *testing.T) {
var v ec2.Instance

Expand Down Expand Up @@ -989,6 +1024,25 @@ resource "aws_instance" "foo" {
}
`

const testAccInstanceConfigMultiplePrivateIPs = `
resource "aws_vpc" "foo" {
cidr_block = "10.1.0.0/16"
}

resource "aws_subnet" "foo" {
cidr_block = "10.1.1.0/24"
vpc_id = "${aws_vpc.foo.id}"
}

resource "aws_instance" "foo" {
ami = "ami-c5eabbf5"
instance_type = "t2.micro"
subnet_id = "${aws_subnet.foo.id}"
private_ip = "10.1.1.42"
private_ip_addresse = ["10.1.1.43","10.1.1.44"]
}
`

const testAccInstanceConfigAssociatePublicIPAndPrivateIP = `
resource "aws_vpc" "foo" {
cidr_block = "10.1.0.0/16"
Expand Down
2 changes: 2 additions & 0 deletions website/source/docs/providers/aws/r/instance.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ instances. See [Shutdown Behavior](https://docs.aws.amazon.com/AWSEC2/latest/Use
* `associate_public_ip_address` - (Optional) Associate a public ip address with an instance in a VPC. Boolean value.
* `private_ip` - (Optional) Private IP address to associate with the
instance in a VPC.
* `private_ip_addresses` - (Optional) Multiple private IP addresses for the instance network card with index 0,
starting from the secondary private address up to the [limit for instance type](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html#AvailableIpPerENI).
* `source_dest_check` - (Optional) Controls if traffic is routed to the instance when
the destination address does not match the instance. Used for NAT or VPNs. Defaults true.
* `user_data` - (Optional) The user data to provide when launching the instance.
Expand Down