Skip to content

Commit

Permalink
New Data Source: aws_instances
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko committed Nov 13, 2017
1 parent 8297de7 commit f0c44ac
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 0 deletions.
106 changes: 106 additions & 0 deletions aws/data_source_aws_instances.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package aws

import (
"fmt"
"log"
"time"

"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/terraform/helper/schema"
)

func dataSourceAwsInstances() *schema.Resource {
return &schema.Resource{
Read: dataSourceAwsInstancesRead,

Schema: map[string]*schema.Schema{
"filter": dataSourceFiltersSchema(),
"instance_tags": tagsSchemaComputed(),

"ids": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"private_ips": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"public_ips": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
}
}

func dataSourceAwsInstancesRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn

filters, filtersOk := d.GetOk("filter")
tags, tagsOk := d.GetOk("instance_tags")

if !filtersOk && !tagsOk {
return fmt.Errorf("One of filters or instance_tags must be assigned")
}

params := &ec2.DescribeInstancesInput{}
if filtersOk {
params.Filters = buildAwsDataSourceFilters(filters.(*schema.Set))
}
if tagsOk {
params.Filters = append(params.Filters, buildEC2TagFilterList(
tagsFromMap(tags.(map[string]interface{})),
)...)
}

log.Printf("[INFO] Describing EC2 instances: %s", params)

var instanceIds, privateIps, publicIps []string
err := conn.DescribeInstancesPages(params, func(resp *ec2.DescribeInstancesOutput, isLast bool) bool {
// 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" {
instanceIds = append(instanceIds, *instance.InstanceId)
if instance.PrivateIpAddress != nil {
privateIps = append(privateIps, *instance.PrivateIpAddress)
}
if instance.PublicIpAddress != nil {
publicIps = append(publicIps, *instance.PublicIpAddress)
}
}
}
}
return !isLast
})
if err != nil {
return err
}

if len(instanceIds) < 1 {
return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.")
}

log.Printf("[DEBUG] Found %d instances via given filter", len(instanceIds))

d.SetId(time.Now().String())
err = d.Set("ids", instanceIds)
if err != nil {
return err
}

err = d.Set("private_ips", privateIps)
if err != nil {
return err
}

err = d.Set("public_ips", publicIps)
if err != nil {
return err
}

return nil
}
115 changes: 115 additions & 0 deletions aws/data_source_aws_instances_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package aws

import (
"fmt"
"testing"

"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
)

func TestAccAWSInstancesDataSource_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccInstancesDataSourceConfig_ids,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.aws_instances.test", "ids.#", "3"),
resource.TestCheckResourceAttr("data.aws_instances.test", "private_ips.#", "3"),
resource.TestCheckResourceAttr("data.aws_instances.test", "public_ips.#", "3"),
),
},
},
})
}

func TestAccAWSInstancesDataSource_tags(t *testing.T) {
rInt := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccInstancesDataSourceConfig_tags(rInt),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.aws_instances.test", "ids.#", "5"),
resource.TestCheckResourceAttr("data.aws_instances.test", "private_ips.#", "5"),
resource.TestCheckResourceAttr("data.aws_instances.test", "public_ips.#", "5"),
),
},
},
})
}

const testAccInstancesDataSourceConfig_ids = `
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = ["099720109477"] # Canonical
}
resource "aws_instance" "test" {
count = 3
ami = "${data.aws_ami.ubuntu.id}"
instance_type = "t2.micro"
tags {
Name = "TfAccTest"
}
}
data "aws_instances" "test" {
filter {
name = "instance-id"
values = ["${aws_instance.test.*.id}"]
}
}
`

func testAccInstancesDataSourceConfig_tags(rInt int) string {
return fmt.Sprintf(`
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = ["099720109477"] # Canonical
}
resource "aws_instance" "test" {
count = 5
ami = "${data.aws_ami.ubuntu.id}"
instance_type = "t2.micro"
tags {
Name = "TfAccTest-HelloWorld"
TestSeed = "%d"
}
}
data "aws_instances" "test" {
instance_tags {
Name = "${aws_instance.test.0.tags["Name"]}"
TestSeed = "%d"
}
}
`, rInt, rInt)
}
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ func Provider() terraform.ResourceProvider {
"aws_iam_user": dataSourceAwsIAMUser(),
"aws_internet_gateway": dataSourceAwsInternetGateway(),
"aws_instance": dataSourceAwsInstance(),
"aws_instances": dataSourceAwsInstances(),
"aws_ip_ranges": dataSourceAwsIPRanges(),
"aws_kinesis_stream": dataSourceAwsKinesisStream(),
"aws_kms_alias": dataSourceAwsKmsAlias(),
Expand Down
3 changes: 3 additions & 0 deletions website/aws.erb
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@
<li<%= sidebar_current("docs-aws-datasource-instance") %>>
<a href="/docs/providers/aws/d/instance.html">aws_instance</a>
</li>
<li<%= sidebar_current("docs-aws-datasource-instances") %>>
<a href="/docs/providers/aws/d/instances.html">aws_instances</a>
</li>
<li<%= sidebar_current("docs-aws-datasource-internet-gateway") %>>
<a href="/docs/providers/aws/d/internet_gateway.html">aws_internet_gateway</a>
</li>
Expand Down
55 changes: 55 additions & 0 deletions website/docs/d/instances.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
layout: "aws"
page_title: "AWS: aws_instances"
sidebar_current: "docs-aws-datasource-instances"
description: |-
Get information on an Amazon EC2 instances.
---

# aws_instances

Use this data source to get IDs or IPs of Amazon EC2 instances to be referenced elsewhere,
e.g. to allow easier migration from another management solution
or to make it easier for an operator to connect through bastion host(s).

-> **Note:** It's a best practice to expose instance details via [outputs](https://www.terraform.io/docs/configuration/outputs.html)
and [remote state](https://www.terraform.io/docs/state/remote.html) and
**use [`terraform_remote_state`](https://www.terraform.io/docs/providers/terraform/d/remote_state.html)
data source instead** if you manage referenced instances via Terraform.

~> **Note:** It's strongly discouraged to use this data source for querying ephemeral
instances (e.g. managed via autoscaling group), as the output may change at any time
and you'd need to re-run `apply` every time an instance comes up or dies.

## Example Usage

```hcl
data "aws_instances" "test" {
instance_tags {
Role = "HardWorker"
}
}
resource "aws_eip" "test" {
count = "${length(data.aws_instances.test.ids)}"
instance = "${data.aws_instances.test.ids[count.index]}"
}
```

## Argument Reference

* `instance_tags` - (Optional) A mapping of tags, each pair of which must
exactly match a pair on desired instances.

* `filter` - (Optional) One or more name/value pairs to use as filters. There are
several valid keys, for a full reference, check out
[describe-instances in the AWS CLI reference][1].

## Attributes Reference

* `ids` - IDs of instances found through the filter
* `private_ips` - Private IP addresses of instances found through the filter
* `public_ips` - Public IP addresses of instances found through the filter


[1]: http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html

0 comments on commit f0c44ac

Please sign in to comment.