From ff43e3171cdc8bc5844dfd3d25d053cb5a5b3e0d Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Thu, 16 Nov 2017 21:45:53 +0900 Subject: [PATCH 1/2] New Datasource: aws_network_interface --- aws/data_source_aws_network_interface.go | 174 ++++++++++++++++++ aws/data_source_aws_network_interface_test.go | 57 ++++++ aws/provider.go | 1 + aws/structure.go | 28 +++ website/aws.erb | 4 + .../docs/d/network_interface.html.markdown | 47 +++++ 6 files changed, 311 insertions(+) create mode 100644 aws/data_source_aws_network_interface.go create mode 100644 aws/data_source_aws_network_interface_test.go create mode 100644 website/docs/d/network_interface.html.markdown diff --git a/aws/data_source_aws_network_interface.go b/aws/data_source_aws_network_interface.go new file mode 100644 index 000000000000..f0df474727ca --- /dev/null +++ b/aws/data_source_aws_network_interface.go @@ -0,0 +1,174 @@ +package aws + +import ( + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform/helper/schema" +) + +func dataSourceAwsNetworkInterface() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsNetworkInterfaceRead, + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + }, + "association": &schema.Schema{ + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allocation_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "association_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "ip_owner_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "public_dns_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "public_ip": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "attachment": &schema.Schema{ + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "attachment_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "device_index": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + }, + "instance_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "instance_owner_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "availability_zone": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "security_groups": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "interface_type": { + Type: schema.TypeString, + Computed: true, + }, + "ipv6_addresses": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "mac_address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "owner_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "private_dns_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "private_ip": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "private_ips": &schema.Schema{ + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "requester_id": { + Type: schema.TypeString, + Computed: true, + }, + "subnet_id": { + Type: schema.TypeString, + Computed: true, + }, + "vpc_id": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsSchemaComputed(), + }, + } +} + +func dataSourceAwsNetworkInterfaceRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + input := &ec2.DescribeNetworkInterfacesInput{ + NetworkInterfaceIds: []*string{aws.String(d.Get("id").(string))}, + } + + resp, err := conn.DescribeNetworkInterfaces(input) + if err != nil { + return err + } + if resp == nil || len(resp.NetworkInterfaces) == 0 { + return fmt.Errorf("no matching network interface found") + } + if len(resp.NetworkInterfaces) > 1 { + return fmt.Errorf("multiple network interfaces matched") + } + + eni := resp.NetworkInterfaces[0] + + d.SetId(*eni.NetworkInterfaceId) + if eni.Association != nil { + d.Set("association", flattenEc2NetworkInterfaceAssociation(eni.Association)) + } + if eni.Attachment != nil { + attachment := []map[string]interface{}{flattenAttachment(eni.Attachment)} + d.Set("attachment", attachment) + } + d.Set("availability_zone", eni.AvailabilityZone) + d.Set("description", eni.Description) + d.Set("security_groups", flattenGroupIdentifiers(eni.Groups)) + d.Set("interface_type", eni.InterfaceType) + d.Set("ipv6_addresses", flattenEc2NetworkInterfaceIpv6Address(eni.Ipv6Addresses)) + d.Set("mac_address", eni.MacAddress) + d.Set("owner_id", eni.OwnerId) + d.Set("private_dns_name", eni.PrivateDnsName) + d.Set("private_id", eni.PrivateIpAddress) + d.Set("private_ips", flattenNetworkInterfacesPrivateIPAddresses(eni.PrivateIpAddresses)) + d.Set("requester_id", eni.RequesterId) + d.Set("subnet_id", eni.SubnetId) + d.Set("vpc_id", eni.VpcId) + d.Set("tags", tagsToMap(eni.TagSet)) + return nil +} diff --git a/aws/data_source_aws_network_interface_test.go b/aws/data_source_aws_network_interface_test.go new file mode 100644 index 000000000000..f598b621059f --- /dev/null +++ b/aws/data_source_aws_network_interface_test.go @@ -0,0 +1,57 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccDataSourceAwsNetworkInterface_basic(t *testing.T) { + rName := acctest.RandString(5) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsNetworkInterface_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.aws_network_interface.test", "private_ips.#", "1"), + resource.TestCheckResourceAttr("data.aws_network_interface.test", "security_groups.#", "1"), + ), + }, + }, + }) +} + +func testAccDataSourceAwsNetworkInterface_basic(rName string) string { + return fmt.Sprintf(` +data "aws_availability_zones" "available" {} + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + cidr_block = "10.0.0.0/24" + availability_zone = "${data.aws_availability_zones.available.names[0]}" + vpc_id = "${aws_vpc.test.id}" +} + +resource "aws_security_group" "test" { + name = "tf-sg-%s" + vpc_id = "${aws_vpc.test.id}" +} + +resource "aws_network_interface" "test" { + subnet_id = "${aws_subnet.test.id}" + private_ips = ["10.0.0.50"] + security_groups = ["${aws_security_group.test.id}"] +} + +data "aws_network_interface" "test" { + id = "${aws_network_interface.test.id}" +} + `, rName) +} diff --git a/aws/provider.go b/aws/provider.go index 2f75284e220b..a3804550da81 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -205,6 +205,7 @@ func Provider() terraform.ResourceProvider { "aws_kms_ciphertext": dataSourceAwsKmsCiphertext(), "aws_kms_secret": dataSourceAwsKmsSecret(), "aws_nat_gateway": dataSourceAwsNatGateway(), + "aws_network_interface": dataSourceAwsNetworkInterface(), "aws_partition": dataSourceAwsPartition(), "aws_prefix_list": dataSourceAwsPrefixList(), "aws_rds_cluster": dataSourceAwsRdsCluster(), diff --git a/aws/structure.go b/aws/structure.go index 2aee465c24ae..39030cf83d65 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -797,6 +797,34 @@ func flattenAttachment(a *ec2.NetworkInterfaceAttachment) map[string]interface{} return att } +func flattenEc2NetworkInterfaceAssociation(a *ec2.NetworkInterfaceAssociation) []map[string]interface{} { + att := make(map[string]interface{}) + if a.AllocationId != nil { + att["allocation_id"] = *a.AllocationId + } + if a.AssociationId != nil { + att["association_id"] = *a.AssociationId + } + if a.IpOwnerId != nil { + att["ip_owner_id"] = *a.IpOwnerId + } + if a.PublicDnsName != nil { + att["public_dns_name"] = *a.PublicDnsName + } + if a.PublicIp != nil { + att["public_ip"] = *a.PublicIp + } + return []map[string]interface{}{att} +} + +func flattenEc2NetworkInterfaceIpv6Address(niia []*ec2.NetworkInterfaceIpv6Address) []string { + ips := make([]string, 0, len(niia)) + for _, v := range niia { + ips = append(ips, *v.Ipv6Address) + } + return ips +} + func flattenElastiCacheSecurityGroupNames(securityGroups []*elasticache.CacheSecurityGroupMembership) []string { result := make([]string, 0, len(securityGroups)) for _, sg := range securityGroups { diff --git a/website/aws.erb b/website/aws.erb index 7c085d7b6467..70a0dc83a5aa 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -157,6 +157,10 @@ > aws_nat_gateway + + > + aws_network_interface + > aws_lb diff --git a/website/docs/d/network_interface.html.markdown b/website/docs/d/network_interface.html.markdown new file mode 100644 index 000000000000..aafe34d1c6d6 --- /dev/null +++ b/website/docs/d/network_interface.html.markdown @@ -0,0 +1,47 @@ +--- +layout: "aws" +page_title: "AWS: aws_network_interface" +sidebar_current: "docs-aws-datasource-network-interface" +description: |- + Get information on anNetwork Interface resource. +--- + +# aws_network_interface + +Use this data source to get information about a Network Interface. + +## Example Usage + +```hcl +data "aws_network_interface" "bar" { + id = "eni-01234567" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `id` – (Required) The identifier for the network interface. + +## Attributes Reference + +See the [Network Interface](/docs/providers/aws/r/network_interface.html) for details on the returned attributes. + +Additionally, the following attributes are exported: + +* `association` - The association information for an Elastic IP address (IPv4) associated with the network interface. See supported fields below. +* `availability_zone` - The Availability Zone. +* `interface_type` - The type of interface. +* `ipv6_addresses` - List of IPv6 addresses to assign to the ENI. +* `mac_address` - The MAC address. +* `owner_id` - The AWS account ID of the owner of the network interface. +* `requester_id` - The ID of the entity that launched the instance on your behalf. + +### `association` + +* `allocation_id` - The allocation ID. +* `association_id` - The association ID. +* `ip_owner_id` - The ID of the Elastic IP address owner. +* `public_dns_name` - The public DNS name. +* `public_ip` - The address of the Elastic IP address bound to the network interface. From f2dbb8cc03798c9d3d4281d17d9e17cc4f0022ae Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Sat, 2 Dec 2017 23:13:21 +0900 Subject: [PATCH 2/2] Reflect reviews --- aws/data_source_aws_network_interface.go | 10 +++++----- aws/structure.go | 4 ++-- website/docs/d/network_interface.html.markdown | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/aws/data_source_aws_network_interface.go b/aws/data_source_aws_network_interface.go index f0df474727ca..6a8f56729ac7 100644 --- a/aws/data_source_aws_network_interface.go +++ b/aws/data_source_aws_network_interface.go @@ -17,7 +17,7 @@ func dataSourceAwsNetworkInterface() *schema.Resource { Required: true, }, "association": &schema.Schema{ - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -45,7 +45,7 @@ func dataSourceAwsNetworkInterface() *schema.Resource { }, }, "attachment": &schema.Schema{ - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -107,7 +107,7 @@ func dataSourceAwsNetworkInterface() *schema.Resource { Computed: true, }, "private_ips": &schema.Schema{ - Type: schema.TypeSet, + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, @@ -143,7 +143,7 @@ func dataSourceAwsNetworkInterfaceRead(d *schema.ResourceData, meta interface{}) return fmt.Errorf("no matching network interface found") } if len(resp.NetworkInterfaces) > 1 { - return fmt.Errorf("multiple network interfaces matched") + return fmt.Errorf("multiple network interfaces matched %s", d.Id()) } eni := resp.NetworkInterfaces[0] @@ -153,7 +153,7 @@ func dataSourceAwsNetworkInterfaceRead(d *schema.ResourceData, meta interface{}) d.Set("association", flattenEc2NetworkInterfaceAssociation(eni.Association)) } if eni.Attachment != nil { - attachment := []map[string]interface{}{flattenAttachment(eni.Attachment)} + attachment := []interface{}{flattenAttachment(eni.Attachment)} d.Set("attachment", attachment) } d.Set("availability_zone", eni.AvailabilityZone) diff --git a/aws/structure.go b/aws/structure.go index 39030cf83d65..21244ef38e9a 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -797,7 +797,7 @@ func flattenAttachment(a *ec2.NetworkInterfaceAttachment) map[string]interface{} return att } -func flattenEc2NetworkInterfaceAssociation(a *ec2.NetworkInterfaceAssociation) []map[string]interface{} { +func flattenEc2NetworkInterfaceAssociation(a *ec2.NetworkInterfaceAssociation) []interface{} { att := make(map[string]interface{}) if a.AllocationId != nil { att["allocation_id"] = *a.AllocationId @@ -814,7 +814,7 @@ func flattenEc2NetworkInterfaceAssociation(a *ec2.NetworkInterfaceAssociation) [ if a.PublicIp != nil { att["public_ip"] = *a.PublicIp } - return []map[string]interface{}{att} + return []interface{}{att} } func flattenEc2NetworkInterfaceIpv6Address(niia []*ec2.NetworkInterfaceIpv6Address) []string { diff --git a/website/docs/d/network_interface.html.markdown b/website/docs/d/network_interface.html.markdown index aafe34d1c6d6..14def5dca255 100644 --- a/website/docs/d/network_interface.html.markdown +++ b/website/docs/d/network_interface.html.markdown @@ -3,7 +3,7 @@ layout: "aws" page_title: "AWS: aws_network_interface" sidebar_current: "docs-aws-datasource-network-interface" description: |- - Get information on anNetwork Interface resource. + Get information on a Network Interface resource. --- # aws_network_interface