provider/aws: Add aws_instance data source

Adds the `aws_instance` data source, tests, and documentation.

```
==> Checking that code complies with gofmt requirements...
go generate $(go list ./... | grep -v /terraform/vendor/)
2017/01/18 11:49:09 Generated command/internal_plugin_list.go
TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSInstanceDataSource -timeout 120m
=== RUN   TestAccAWSInstanceDataSource_basic
--- PASS: TestAccAWSInstanceDataSource_basic (106.24s)
=== RUN   TestAccAWSInstanceDataSource_AzUserData
--- PASS: TestAccAWSInstanceDataSource_AzUserData (108.52s)
=== RUN   TestAccAWSInstanceDataSource_gp2IopsDevice
--- PASS: TestAccAWSInstanceDataSource_gp2IopsDevice (80.71s)
=== RUN   TestAccAWSInstanceDataSource_blockDevices
--- PASS: TestAccAWSInstanceDataSource_blockDevices (94.07s)
=== RUN   TestAccAWSInstanceDataSource_rootInstanceStore
--- PASS: TestAccAWSInstanceDataSource_rootInstanceStore (95.17s)
=== RUN   TestAccAWSInstanceDataSource_privateIP
--- PASS: TestAccAWSInstanceDataSource_privateIP (241.75s)
=== RUN   TestAccAWSInstanceDataSource_keyPair
--- PASS: TestAccAWSInstanceDataSource_keyPair (208.77s)
=== RUN   TestAccAWSInstanceDataSource_VPC
--- PASS: TestAccAWSInstanceDataSource_VPC (109.89s)
=== RUN   TestAccAWSInstanceDataSource_SecurityGroups
--- PASS: TestAccAWSInstanceDataSource_SecurityGroups (118.66s)
=== RUN   TestAccAWSInstanceDataSource_VPCSecurityGroups
--- PASS: TestAccAWSInstanceDataSource_VPCSecurityGroups (136.79s)
PASS
ok      github.com/hashicorp/terraform/builtin/providers/aws    1300.625s
```
This commit is contained in:
Jake Champlin 2017-01-18 12:19:44 -05:00
parent dac527be47
commit 9cbd67dd0b
No known key found for this signature in database
GPG Key ID: DC31F41958EF4AC2
5 changed files with 994 additions and 46 deletions

View File

@ -0,0 +1,349 @@
package aws
import (
"fmt"
"log"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/terraform/helper/schema"
)
func dataSourceAwsInstance() *schema.Resource {
return &schema.Resource{
Read: dataSourceAwsInstanceRead,
Schema: map[string]*schema.Schema{
"filter": dataSourceFiltersSchema(),
"tags": dataSourceTagsSchema(),
"instance_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"ami": {
Type: schema.TypeString,
Computed: true,
},
"instance_type": {
Type: schema.TypeString,
Computed: true,
},
"instance_state": {
Type: schema.TypeString,
Computed: true,
},
"availability_zone": {
Type: schema.TypeString,
Computed: true,
},
"tenancy": {
Type: schema.TypeString,
Computed: true,
},
"key_name": {
Type: schema.TypeString,
Computed: true,
},
"public_dns": {
Type: schema.TypeString,
Computed: true,
},
"public_ip": {
Type: schema.TypeString,
Computed: true,
},
"private_dns": {
Type: schema.TypeString,
Computed: true,
},
"private_ip": {
Type: schema.TypeString,
Computed: true,
},
"iam_instance_profile": {
Type: schema.TypeString,
Computed: true,
},
"subnet_id": {
Type: schema.TypeString,
Computed: true,
},
"network_interface_id": {
Type: schema.TypeString,
Computed: true,
},
"associate_public_ip_address": {
Type: schema.TypeBool,
Computed: true,
},
"ebs_optimized": {
Type: schema.TypeBool,
Computed: true,
},
"source_dest_check": {
Type: schema.TypeBool,
Computed: true,
},
"monitoring": {
Type: schema.TypeBool,
Computed: true,
},
"user_data": {
Type: schema.TypeString,
Computed: true,
},
"security_groups": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"vpc_security_group_ids": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"ephemeral_block_device": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"device_name": {
Type: schema.TypeString,
Required: true,
},
"virtual_name": {
Type: schema.TypeString,
Optional: true,
},
"no_device": {
Type: schema.TypeBool,
Optional: true,
},
},
},
},
"ebs_block_device": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"delete_on_termination": {
Type: schema.TypeBool,
Computed: true,
},
"device_name": {
Type: schema.TypeString,
Computed: true,
},
"encrypted": {
Type: schema.TypeBool,
Computed: true,
},
"iops": {
Type: schema.TypeInt,
Computed: true,
},
"snapshot_id": {
Type: schema.TypeString,
Computed: true,
},
"volume_size": {
Type: schema.TypeInt,
Computed: true,
},
"volume_type": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
"root_block_device": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"delete_on_termination": {
Type: schema.TypeBool,
Computed: true,
},
"iops": {
Type: schema.TypeInt,
Computed: true,
},
"volume_size": {
Type: schema.TypeInt,
Computed: true,
},
"volume_type": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
},
}
}
// dataSourceAwsInstanceRead performs the instanceID lookup
func dataSourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn
filters, filtersOk := d.GetOk("filter")
instanceID, instanceIDOk := d.GetOk("instance_id")
if filtersOk == false && instanceIDOk == false {
return fmt.Errorf("One of filters, or instance_id must be assigned")
}
// Build up search parameters
params := &ec2.DescribeInstancesInput{}
if filtersOk {
params.Filters = buildAwsDataSourceFilters(filters.(*schema.Set))
}
if instanceIDOk {
params.InstanceIds = []*string{aws.String(instanceID.(string))}
}
// Perform the lookup
resp, err := conn.DescribeInstances(params)
if err != nil {
return err
}
// If no instances were returned, return
if len(resp.Reservations) == 0 {
return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.")
}
var filteredInstances []*ec2.Instance
// loop through reservations, and remove terminated instances, populate instance slice
for _, res := range resp.Reservations {
for _, instance := range res.Instances {
if instance.State != nil && *instance.State.Name != "terminated" {
filteredInstances = append(filteredInstances, instance)
}
}
}
var instance *ec2.Instance
if len(filteredInstances) < 1 {
return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.")
}
// (TODO: Support a list of instances to be returned)
// Possibly with a different data source that returns a list of individual instance data sources
if len(filteredInstances) > 1 {
return fmt.Errorf("Your query returned more than one result. Please try a more " +
"specific search criteria.")
} else {
instance = filteredInstances[0]
}
log.Printf("[DEBUG] aws_instance - Single Instance ID found: %s", *instance.InstanceId)
return instanceDescriptionAttributes(d, instance, conn)
}
// Populate instance attribute fields with the returned instance
func instanceDescriptionAttributes(d *schema.ResourceData, instance *ec2.Instance, conn *ec2.EC2) error {
d.SetId(*instance.InstanceId)
// Set the easy attributes
d.Set("instance_state", instance.State.Name)
if instance.Placement != nil {
d.Set("availability_zone", instance.Placement.AvailabilityZone)
}
if instance.Placement.Tenancy != nil {
d.Set("tenancy", instance.Placement.Tenancy)
}
d.Set("ami", instance.ImageId)
d.Set("instance_type", instance.InstanceType)
d.Set("key_name", instance.KeyName)
d.Set("public_dns", instance.PublicDnsName)
d.Set("public_ip", instance.PublicIpAddress)
d.Set("private_dns", instance.PrivateDnsName)
d.Set("private_ip", instance.PrivateIpAddress)
d.Set("iam_instance_profile", iamInstanceProfileArnToName(instance.IamInstanceProfile))
// iterate through network interfaces, and set subnet, network_interface, public_addr
if len(instance.NetworkInterfaces) > 0 {
for _, ni := range instance.NetworkInterfaces {
if *ni.Attachment.DeviceIndex == 0 {
d.Set("subnet_id", ni.SubnetId)
d.Set("network_interface_id", ni.NetworkInterfaceId)
d.Set("associate_public_ip_address", ni.Association != nil)
}
}
} else {
d.Set("subnet_id", instance.SubnetId)
d.Set("network_interface_id", "")
}
d.Set("ebs_optimized", instance.EbsOptimized)
if instance.SubnetId != nil && *instance.SubnetId != "" {
d.Set("source_dest_check", instance.SourceDestCheck)
}
if instance.Monitoring != nil && instance.Monitoring.State != nil {
monitoringState := *instance.Monitoring.State
d.Set("monitoring", monitoringState == "enabled" || monitoringState == "pending")
}
d.Set("tags", dataSourceTags(instance.Tags))
// Security Groups
if err := readSecurityGroups(d, instance); err != nil {
return err
}
// Block devices
if err := readBlockDevices(d, instance, conn); err != nil {
return err
}
if _, ok := d.GetOk("ephemeral_block_device"); !ok {
d.Set("ephemeral_block_device", []interface{}{})
}
// Lookup and Set Instance Attributes
{
attr, err := conn.DescribeInstanceAttribute(&ec2.DescribeInstanceAttributeInput{
Attribute: aws.String("disableApiTermination"),
InstanceId: aws.String(d.Id()),
})
if err != nil {
return err
}
d.Set("disable_api_termination", attr.DisableApiTermination.Value)
}
{
attr, err := conn.DescribeInstanceAttribute(&ec2.DescribeInstanceAttributeInput{
Attribute: aws.String(ec2.InstanceAttributeNameUserData),
InstanceId: aws.String(d.Id()),
})
if err != nil {
return err
}
if attr.UserData.Value != nil {
d.Set("user_data", userDataHashSum(*attr.UserData.Value))
}
}
return nil
}

View File

@ -0,0 +1,498 @@
package aws
import (
"testing"
"github.com/hashicorp/terraform/helper/resource"
)
func TestAccAWSInstanceDataSource_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccInstanceDataSourceConfig,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.aws_instance.web-instance", "ami", "ami-4fccb37f"),
resource.TestCheckResourceAttr(
"data.aws_instance.web-instance", "tags.#", "1"),
resource.TestCheckResourceAttr(
"data.aws_instance.web-instance", "instance_type", "m1.small"),
),
},
},
})
}
func TestAccAWSInstanceDataSource_AzUserData(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccInstanceDataSourceConfig_AzUserData,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "ami", "ami-4fccb37f"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "tags.#", "1"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "instance_type", "m1.small"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "availability_zone", "us-west-2a"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "user_data", "3dc39dda39be1205215e776bad998da361a5955d"),
),
},
},
})
}
func TestAccAWSInstanceDataSource_gp2IopsDevice(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccInstanceDataSourceConfig_gp2IopsDevice,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "ami", "ami-55a7ea65"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "instance_type", "m3.medium"),
resource.TestCheckResourceAttr(
"aws_instance.foo", "root_block_device.#", "1"),
resource.TestCheckResourceAttr(
"aws_instance.foo", "root_block_device.0.volume_size", "11"),
resource.TestCheckResourceAttr(
"aws_instance.foo", "root_block_device.0.volume_type", "gp2"),
resource.TestCheckResourceAttr(
"aws_instance.foo", "root_block_device.0.iops", "100"),
),
},
},
})
}
func TestAccAWSInstanceDataSource_blockDevices(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccInstanceDataSourceConfig_blockDevices,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "ami", "ami-55a7ea65"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "instance_type", "m3.medium"),
resource.TestCheckResourceAttr(
"aws_instance.foo", "root_block_device.#", "1"),
resource.TestCheckResourceAttr(
"aws_instance.foo", "root_block_device.0.volume_size", "11"),
resource.TestCheckResourceAttr(
"aws_instance.foo", "root_block_device.0.volume_type", "gp2"),
resource.TestCheckResourceAttr(
"aws_instance.foo", "ebs_block_device.#", "3"),
resource.TestCheckResourceAttr(
"aws_instance.foo", "ephemeral_block_device.#", "1"),
),
},
},
})
}
func TestAccAWSInstanceDataSource_rootInstanceStore(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccInstanceDataSourceConfig_rootInstanceStore,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "ami", "ami-44c36524"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "instance_type", "m3.medium"),
resource.TestCheckResourceAttr(
"aws_instance.foo", "ebs_block_device.#", "0"),
resource.TestCheckResourceAttr(
"aws_instance.foo", "ebs_optimized", "false"),
resource.TestCheckResourceAttr(
"aws_instance.foo", "root_block_device.#", "0"),
),
},
},
})
}
func TestAccAWSInstanceDataSource_privateIP(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccInstanceDataSourceConfig_privateIP,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "ami", "ami-c5eabbf5"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "instance_type", "t2.micro"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "private_ip", "10.1.1.42"),
),
},
},
})
}
func TestAccAWSInstanceDataSource_keyPair(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccInstanceDataSourceConfig_keyPair,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "ami", "ami-408c7f28"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "instance_type", "t1.micro"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "tags.#", "1"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "key_name", "tmp-key"),
),
},
},
})
}
func TestAccAWSInstanceDataSource_VPC(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccInstanceDataSourceConfig_VPC,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "ami", "ami-4fccb37f"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "instance_type", "m1.small"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "user_data", "562a3e32810edf6ff09994f050f12e799452379d"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "associate_public_ip_address", "true"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "tenancy", "dedicated"),
),
},
},
})
}
func TestAccAWSInstanceDataSource_SecurityGroups(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccInstanceDataSourceConfig_SecurityGroups,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "ami", "ami-408c7f28"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "instance_type", "m1.small"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "vpc_security_group_ids.#", "0"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "security_groups.#", "1"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "user_data", "3dc39dda39be1205215e776bad998da361a5955d"),
),
},
},
})
}
func TestAccAWSInstanceDataSource_VPCSecurityGroups(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccInstanceDataSourceConfig_VPCSecurityGroups,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "ami", "ami-21f78e11"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "instance_type", "t1.micro"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "security_groups.#", "0"),
resource.TestCheckResourceAttr(
"data.aws_instance.foo", "vpc_security_group_ids.#", "1"),
),
},
},
})
}
// Lookup based on InstanceID
const testAccInstanceDataSourceConfig = `
resource "aws_instance" "web" {
# us-west-2
ami = "ami-4fccb37f"
instance_type = "m1.small"
tags {
Name = "HelloWorld"
}
}
data "aws_instance" "web-instance" {
filter {
name = "instance-id"
values = ["${aws_instance.web.id}"]
}
}
`
// filter on tag, populate more attributes
const testAccInstanceDataSourceConfig_AzUserData = `
resource "aws_instance" "foo" {
# us-west-2
ami = "ami-4fccb37f"
availability_zone = "us-west-2a"
instance_type = "m1.small"
user_data = "foo:-with-character's"
tags {
TFAccTest = "YesThisIsATest"
}
}
data "aws_instance" "foo" {
instance_id = "${aws_instance.foo.id}"
}
`
// GP2IopsDevice
const testAccInstanceDataSourceConfig_gp2IopsDevice = `
resource "aws_instance" "foo" {
# us-west-2
ami = "ami-55a7ea65"
instance_type = "m3.medium"
root_block_device {
volume_type = "gp2"
volume_size = 11
iops = 330
}
}
data "aws_instance" "foo" {
instance_id = "${aws_instance.foo.id}"
}
`
// Block Device
const testAccInstanceDataSourceConfig_blockDevices = `
resource "aws_instance" "foo" {
# us-west-2
ami = "ami-55a7ea65"
instance_type = "m3.medium"
root_block_device {
volume_type = "gp2"
volume_size = 11
}
ebs_block_device {
device_name = "/dev/sdb"
volume_size = 9
}
ebs_block_device {
device_name = "/dev/sdc"
volume_size = 10
volume_type = "io1"
iops = 100
}
# Encrypted ebs block device
ebs_block_device {
device_name = "/dev/sdd"
volume_size = 12
encrypted = true
}
ephemeral_block_device {
device_name = "/dev/sde"
virtual_name = "ephemeral0"
}
}
data "aws_instance" "foo" {
instance_id = "${aws_instance.foo.id}"
}
`
const testAccInstanceDataSourceConfig_rootInstanceStore = `
resource "aws_instance" "foo" {
ami = "ami-44c36524"
instance_type = "m3.medium"
}
data "aws_instance" "foo" {
instance_id = "${aws_instance.foo.id}"
}
`
const testAccInstanceDataSourceConfig_privateIP = `
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"
}
data "aws_instance" "foo" {
instance_id = "${aws_instance.foo.id}"
}
`
const testAccInstanceDataSourceConfig_keyPair = `
provider "aws" {
region = "us-east-1"
}
resource "aws_key_pair" "debugging" {
key_name = "tmp-key"
public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD3F6tyPEFEzV0LX3X8BsXdMsQz1x2cEikKDEY0aIj41qgxMCP/iteneqXSIFZBp5vizPvaoIR3Um9xK7PGoW8giupGn+EPuxIA4cDM4vzOqOkiMPhz5XK0whEjkVzTo4+S0puvDZuwIsdiW9mxhJc7tgBNL0cYlWSYVkz4G/fslNfRPW5mYAM49f4fhtxPb5ok4Q2Lg9dPKVHO/Bgeu5woMc7RY0p1ej6D4CKFE6lymSDJpW0YHX/wqE9+cfEauh7xZcG0q9t2ta6F6fmX0agvpFyZo8aFbXeUBr7osSCJNgvavWbM/06niWrOvYX2xwWdhXmXSrbX8ZbabVohBK41 phodgson@thoughtworks.com"
}
resource "aws_instance" "foo" {
ami = "ami-408c7f28"
instance_type = "t1.micro"
key_name = "${aws_key_pair.debugging.key_name}"
tags {
Name = "testAccInstanceDataSourceConfigKeyPair_TestAMI"
}
}
data "aws_instance" "foo" {
filter {
name = "tag:Name"
values = ["testAccInstanceDataSourceConfigKeyPair_TestAMI"]
}
filter {
name = "key-name"
values = ["${aws_instance.foo.key_name}"]
}
}
`
const testAccInstanceDataSourceConfig_VPC = `
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" {
# us-west-2
ami = "ami-4fccb37f"
instance_type = "m1.small"
subnet_id = "${aws_subnet.foo.id}"
associate_public_ip_address = true
tenancy = "dedicated"
# pre-encoded base64 data
user_data = "3dc39dda39be1205215e776bad998da361a5955d"
}
data "aws_instance" "foo" {
instance_id = "${aws_instance.foo.id}"
}
`
const testAccInstanceDataSourceConfig_SecurityGroups = `
provider "aws" {
region = "us-east-1"
}
resource "aws_security_group" "tf_test_foo" {
name = "tf_test_foo"
description = "foo"
ingress {
protocol = "icmp"
from_port = -1
to_port = -1
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "foo" {
ami = "ami-408c7f28"
instance_type = "m1.small"
security_groups = ["${aws_security_group.tf_test_foo.name}"]
user_data = "foo:-with-character's"
}
data "aws_instance" "foo" {
instance_id = "${aws_instance.foo.id}"
}
`
const testAccInstanceDataSourceConfig_VPCSecurityGroups = `
resource "aws_internet_gateway" "gw" {
vpc_id = "${aws_vpc.foo.id}"
}
resource "aws_vpc" "foo" {
cidr_block = "10.1.0.0/16"
tags {
Name = "tf-network-test"
}
}
resource "aws_security_group" "tf_test_foo" {
name = "tf_test_foo"
description = "foo"
vpc_id="${aws_vpc.foo.id}"
ingress {
protocol = "icmp"
from_port = -1
to_port = -1
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_subnet" "foo" {
cidr_block = "10.1.1.0/24"
vpc_id = "${aws_vpc.foo.id}"
}
resource "aws_instance" "foo_instance" {
ami = "ami-21f78e11"
instance_type = "t1.micro"
vpc_security_group_ids = ["${aws_security_group.tf_test_foo.id}"]
subnet_id = "${aws_subnet.foo.id}"
depends_on = ["aws_internet_gateway.gw"]
}
data "aws_instance" "foo" {
instance_id = "${aws_instance.foo_instance.id}"
}
`

View File

@ -161,6 +161,7 @@ func Provider() terraform.ResourceProvider {
"aws_iam_account_alias": dataSourceAwsIamAccountAlias(),
"aws_iam_policy_document": dataSourceAwsIamPolicyDocument(),
"aws_iam_server_certificate": dataSourceAwsIAMServerCertificate(),
"aws_instance": dataSourceAwsInstance(),
"aws_ip_ranges": dataSourceAwsIPRanges(),
"aws_prefix_list": dataSourceAwsPrefixList(),
"aws_redshift_service_account": dataSourceAwsRedshiftServiceAccount(),

View File

@ -526,52 +526,8 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
d.Set("tags", tagsToMap(instance.Tags))
// Determine whether we're referring to security groups with
// IDs or names. We use a heuristic to figure this out. By default,
// we use IDs if we're in a VPC. However, if we previously had an
// all-name list of security groups, we use names. Or, if we had any
// IDs, we use IDs.
useID := instance.SubnetId != nil && *instance.SubnetId != ""
if v := d.Get("security_groups"); v != nil {
match := useID
sgs := v.(*schema.Set).List()
if len(sgs) > 0 {
match = false
for _, v := range v.(*schema.Set).List() {
if strings.HasPrefix(v.(string), "sg-") {
match = true
break
}
}
}
useID = match
}
// Build up the security groups
sgs := make([]string, 0, len(instance.SecurityGroups))
if useID {
for _, sg := range instance.SecurityGroups {
sgs = append(sgs, *sg.GroupId)
}
log.Printf("[DEBUG] Setting Security Group IDs: %#v", sgs)
if err := d.Set("vpc_security_group_ids", sgs); err != nil {
return err
}
if err := d.Set("security_groups", []string{}); err != nil {
return err
}
} else {
for _, sg := range instance.SecurityGroups {
sgs = append(sgs, *sg.GroupName)
}
log.Printf("[DEBUG] Setting Security Group Names: %#v", sgs)
if err := d.Set("security_groups", sgs); err != nil {
return err
}
if err := d.Set("vpc_security_group_ids", []string{}); err != nil {
return err
}
if err := readSecurityGroups(d, instance); err != nil {
return err
}
if err := readBlockDevices(d, instance, conn); err != nil {
@ -1013,6 +969,57 @@ func readBlockDeviceMappingsFromConfig(
return blockDevices, nil
}
// Determine whether we're referring to security groups with
// IDs or names. We use a heuristic to figure this out. By default,
// we use IDs if we're in a VPC. However, if we previously had an
// all-name list of security groups, we use names. Or, if we had any
// IDs, we use IDs.
func readSecurityGroups(d *schema.ResourceData, instance *ec2.Instance) error {
useID := instance.SubnetId != nil && *instance.SubnetId != ""
if v := d.Get("security_groups"); v != nil {
match := useID
sgs := v.(*schema.Set).List()
if len(sgs) > 0 {
match = false
for _, v := range v.(*schema.Set).List() {
if strings.HasPrefix(v.(string), "sg-") {
match = true
break
}
}
}
useID = match
}
// Build up the security groups
sgs := make([]string, 0, len(instance.SecurityGroups))
if useID {
for _, sg := range instance.SecurityGroups {
sgs = append(sgs, *sg.GroupId)
}
log.Printf("[DEBUG] Setting Security Group IDs: %#v", sgs)
if err := d.Set("vpc_security_group_ids", sgs); err != nil {
return err
}
if err := d.Set("security_groups", []string{}); err != nil {
return err
}
} else {
for _, sg := range instance.SecurityGroups {
sgs = append(sgs, *sg.GroupName)
}
log.Printf("[DEBUG] Setting Security Group Names: %#v", sgs)
if err := d.Set("security_groups", sgs); err != nil {
return err
}
if err := d.Set("vpc_security_group_ids", []string{}); err != nil {
return err
}
}
return nil
}
type awsInstanceOpts struct {
BlockDeviceMappings []*ec2.BlockDeviceMapping
DisableAPITermination *bool

View File

@ -0,0 +1,93 @@
---
layout: "aws"
page_title: "AWS: aws_instance"
sidebar_current: "docs-aws-datasource-instance"
description: |-
Get information on a Amazon EC2 Instance.
---
# aws\_instance
Use this data source to get the ID of an EC2 Instance for use in other
resources.
## Example Usage
```
data "aws_instance" "foo" {
instance_id = "i-instanceid"
filter {
name = "image-id"
values = ["ami-xxxxxxxx"]
}
filter {
name = "tag:Name"
values = ["instance-name-tag"]
}
}
```
## Argument Reference
* `instance_id` - (Optional) Specify the exact Instance ID to populate the data source with.
* `filter` - (Optional) One or more name/value pairs to filter off of. There are
several valid keys, for a full reference, check out
[describe-instances in the AWS CLI reference][1].
~> **NOTE:** At least one of `filter` or `instance_id` must be specified.
~> **NOTE:** If more or less than a single match is returned by the search,
Terraform will fail. Ensure that your search is specific enough to return
a single Instance ID only.
## Attributes Reference
`id` is set to the ID of the found Instance. In addition, the following attributes
are exported:
~> **NOTE:** Some values are not always set and may not be available for
interpolation.
* `associate_public_ip_address` - Whether or not the instance is associated with a public ip address or not (Boolean).
* `availability_zone` - The availability zone of the instance.
* `ebs_block_device` - The EBS block device mappings of the instance.
* `delete_on_termination` - If the EBS volume will be deleted on termination.
* `device_name` - The physical name of the device.
* `encrypted` - If the EBS volume is encrypted.
* `iops` - `0` If the EBS volume is not a provisioned IOPS image, otherwise the supported IOPS count.
* `snapshot_id` - The ID of the snapshot.
* `volume_size` - The size of the volume, in GiB.
* `volume_type` - The volume type.
* `ebs_optimized` - Whether the instance is ebs optimized or not (Boolean).
* `ephemeral_block_device` - The ephemeral block device mappings of the instance.
* `device_name` - The physical name of the device.
* `no_device` - Whether the specified device included in the device mapping was suppressed or not (Boolean).
* `virtual_name` - The virtual device name
* `iam_instance_profile` - The instance profile associated with the instance. Specified as an ARN.
* `instance_type` - The type of the instance.
* `key_name` - The key name of the instance.
* `monitoring` - Whether detailed monitoring is enabled or disabled for the instance (Boolean).
* `network_interface_id` - The ID of the network interface that was created with the instance.
* `placement_group` - The placement group of the instance.
* `private_dns` - The private DNS name assigned to the instance. Can only be
used inside the Amazon EC2, and only available if you've enabled DNS hostnames
for your VPC.
* `private_ip` - The private IP address assigned to the instance.
* `public_dns` - The public DNS name assigned to the instance. For EC2-VPC, this
is only available if you've enabled DNS hostnames for your VPC.
* `public_ip` - The public IP address assigned to the instance, if applicable. **NOTE**: If you are using an [`aws_eip`](/docs/providers/aws/r/eip.html) with your instance, you should refer to the EIP's address directly and not use `public_ip`, as this field will change after the EIP is attached.
* `root_block_device` - The root block device mappings of the instance
* `delete_on_termination` - If the root block device will be deleted on termination.
* `iops` - `0` If the volume is not a provisioned IOPS image, otherwise the supported IOPS count.
* `volume_size` - The size of the volume, in GiB.
* `volume_type` - The type of the volume.
* `security_groups` - The associated security groups.
* `source_dest_check` - Whether the network interface performs source/destination checking (Boolean).
* `subnet_id` - The VPC subnet ID.
* `user_data` - The User Data supplied to the instance.
* `tags` - A mapping of tags assigned to the instance.
* `tenancy` - The tenancy of the instance (dedicated | default | host ).
* `vpc_security_group_ids` - The associated security groups in non-default VPC.
[1]: http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html