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

Support Availability Zone ID in data sources #6686

Merged
merged 2 commits into from
Dec 3, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
17 changes: 13 additions & 4 deletions aws/data_source_aws_availability_zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ func dataSourceAwsAvailabilityZone() *schema.Resource {
Optional: true,
Computed: true,
},

"zone_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
},
}
}
Expand All @@ -44,10 +50,12 @@ func dataSourceAwsAvailabilityZoneRead(d *schema.ResourceData, meta interface{})

req := &ec2.DescribeAvailabilityZonesInput{}

if name := d.Get("name"); name != "" {
req.ZoneNames = []*string{aws.String(name.(string))}
if v := d.Get("name").(string); v != "" {
req.ZoneNames = []*string{aws.String(v)}
}
if v := d.Get("zone_id").(string); v != "" {
req.ZoneIds = []*string{aws.String(v)}
}

req.Filters = buildEC2AttributeFilterList(
map[string]string{
"state": d.Get("state").(string),
Expand Down Expand Up @@ -78,11 +86,12 @@ func dataSourceAwsAvailabilityZoneRead(d *schema.ResourceData, meta interface{})
// work regardless of region.
nameSuffix := (*az.ZoneName)[len(*az.RegionName):]

d.SetId(*az.ZoneName)
d.SetId(aws.StringValue(az.ZoneName))
d.Set("name", az.ZoneName)
d.Set("name_suffix", nameSuffix)
d.Set("region", az.RegionName)
d.Set("state", az.State)
d.Set("zone_id", az.ZoneId)

return nil
}
42 changes: 16 additions & 26 deletions aws/data_source_aws_availability_zone_test.go
Original file line number Diff line number Diff line change
@@ -1,51 +1,37 @@
package aws

import (
"fmt"
"testing"

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

func TestAccDataSourceAwsAvailabilityZone(t *testing.T) {
ds1ResourceName := "data.aws_availability_zone.by_name"
ds2ResourceName := "data.aws_availability_zone.by_zone_id"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAwsAvailabilityZoneConfig,
Check: resource.ComposeTestCheckFunc(
testAccDataSourceAwsAvailabilityZoneCheck("data.aws_availability_zone.by_name"),
resource.TestCheckResourceAttr(ds1ResourceName, "name", "us-west-2a"),
resource.TestCheckResourceAttr(ds1ResourceName, "name_suffix", "a"),
resource.TestCheckResourceAttr(ds1ResourceName, "region", "us-west-2"),
resource.TestCheckResourceAttrSet(ds1ResourceName, "zone_id"),

resource.TestCheckResourceAttr(ds2ResourceName, "name", "us-west-2a"),
resource.TestCheckResourceAttr(ds2ResourceName, "name_suffix", "a"),
resource.TestCheckResourceAttr(ds2ResourceName, "region", "us-west-2"),
resource.TestCheckResourceAttrPair(ds2ResourceName, "zone_id", ds1ResourceName, "zone_id"),
),
},
},
})
}

func testAccDataSourceAwsAvailabilityZoneCheck(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("root module has no resource called %s", name)
}

attr := rs.Primary.Attributes

if attr["name"] != "us-west-2a" {
return fmt.Errorf("bad name %s", attr["name"])
}
if attr["name_suffix"] != "a" {
return fmt.Errorf("bad name_suffix %s", attr["name_suffix"])
}
if attr["region"] != "us-west-2" {
return fmt.Errorf("bad region %s", attr["region"])
}

return nil
}
}

const testAccDataSourceAwsAvailabilityZoneConfig = `
provider "aws" {
region = "us-west-2"
Expand All @@ -54,4 +40,8 @@ provider "aws" {
data "aws_availability_zone" "by_name" {
name = "us-west-2a"
}

data "aws_availability_zone" "by_zone_id" {
zone_id = "${data.aws_availability_zone.by_name.zone_id}"
}
`
41 changes: 34 additions & 7 deletions aws/data_source_aws_availability_zones.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ func dataSourceAwsAvailabilityZones() *schema.Resource {
ec2.AvailabilityZoneStateUnavailable,
}, false),
},
"zone_ids": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
}
}
Expand Down Expand Up @@ -59,16 +64,38 @@ func dataSourceAwsAvailabilityZonesRead(d *schema.ResourceData, meta interface{}
return fmt.Errorf("Error fetching Availability Zones: %s", err)
}

raw := make([]string, len(resp.AvailabilityZones))
for i, v := range resp.AvailabilityZones {
raw[i] = *v.ZoneName
}
azs := resp.AvailabilityZones
sort.Sort(availabilityZones(azs))
bflad marked this conversation as resolved.
Show resolved Hide resolved

sort.Strings(raw)
names := []string{}
zoneIds := []string{}
for _, v := range azs {
names = append(names, aws.StringValue(v.ZoneName))
zoneIds = append(zoneIds, aws.StringValue(v.ZoneId))
}

if err := d.Set("names", raw); err != nil {
return fmt.Errorf("Error setting Availability Zones: %s", err)
if err := d.Set("names", names); err != nil {
return fmt.Errorf("Error setting Availability Zone names: %s", err)
}
if err := d.Set("zone_ids", zoneIds); err != nil {
return fmt.Errorf("Error setting Availability Zone IDs: %s", err)
}

return nil
}

// Ensure that indexes of returned AZ names and zone IDs correspond.
type availabilityZones []*ec2.AvailabilityZone

func (azs availabilityZones) Len() int {
return len(azs)
}

func (azs availabilityZones) Swap(i, j int) {
azs[i], azs[j] = azs[j], azs[i]
}

func (azs availabilityZones) Less(i, j int) bool {
// Sort by AZ name.
return aws.StringValue(azs[i].ZoneName) < aws.StringValue(azs[j].ZoneName)
}
66 changes: 65 additions & 1 deletion aws/data_source_aws_availability_zones_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,70 @@ import (
"strconv"
"testing"

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

func TestAvailabilityZonesSort(t *testing.T) {
azs := []*ec2.AvailabilityZone{
{
ZoneName: aws.String("name_YYY"),
ZoneId: aws.String("id_YYY"),
},
{
ZoneName: aws.String("name_AAA"),
ZoneId: aws.String("id_AAA"),
},
{
ZoneName: aws.String("name_ZZZ"),
ZoneId: aws.String("id_ZZZ"),
},
{
ZoneName: aws.String("name_BBB"),
ZoneId: aws.String("id_BBB"),
},
}
sort.Sort(availabilityZones(azs))

cases := []struct {
Index int
ZoneName string
ZoneId string
}{
{
Index: 0,
ZoneName: "name_AAA",
ZoneId: "id_AAA",
},
{
Index: 1,
ZoneName: "name_BBB",
ZoneId: "id_BBB",
},
{
Index: 2,
ZoneName: "name_YYY",
ZoneId: "id_YYY",
},
{
Index: 3,
ZoneName: "name_ZZZ",
ZoneId: "id_ZZZ",
},
}
for _, tc := range cases {
az := azs[tc.Index]
if aws.StringValue(az.ZoneName) != tc.ZoneName {
t.Fatalf("AvailabilityZones index %d got zone name %s, expected %s", tc.Index, aws.StringValue(az.ZoneName), tc.ZoneName)
}
if aws.StringValue(az.ZoneId) != tc.ZoneId {
t.Fatalf("AvailabilityZones index %d got zone ID %s, expected %s", tc.Index, aws.StringValue(az.ZoneId), tc.ZoneId)
}
}
}

func TestAccAWSAvailabilityZones_basic(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Expand Down Expand Up @@ -92,7 +152,7 @@ func testAccCheckAwsAvailabilityZoneState(n string) resource.TestCheckFunc {
func testAccCheckAwsAvailabilityZonesBuildAvailable(attrs map[string]string) ([]string, error) {
v, ok := attrs["names.#"]
if !ok {
return nil, fmt.Errorf("Available AZ list is missing.")
return nil, fmt.Errorf("Available AZ name list is missing.")
}
qty, err := strconv.Atoi(v)
if err != nil {
Expand All @@ -101,6 +161,10 @@ func testAccCheckAwsAvailabilityZonesBuildAvailable(attrs map[string]string) ([]
if qty < 1 {
return nil, fmt.Errorf("No AZs found in region, this is probably a bug.")
}
_, ok = attrs["zone_ids.#"]
if !ok {
return nil, fmt.Errorf("Available AZ ID list is missing.")
}
zones := make([]string, qty)
for n := range zones {
zone, ok := attrs["names."+strconv.Itoa(n)]
Expand Down
4 changes: 4 additions & 0 deletions website/docs/d/availability_zone.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ zone whose data will be exported as attributes.
* `state` - (Optional) A specific availability zone state to require. May
be any of `"available"`, `"information"` or `"impaired"`.

* `zone_id` - (Optional) The zone ID of the availability zone to select.

All reasonable uses of this data source will specify `name`, since `state`
alone would match a single AZ only in a region that itself has only one AZ.

Expand All @@ -96,3 +98,5 @@ In addition to all arguments above, the following attributes are exported:
uniquely identifying the AZ within its region.

* `state` - The current state of the AZ.

* `zone_id` - (Optional) The zone ID of the selected availability zone.
3 changes: 3 additions & 0 deletions website/docs/d/availability_zones.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,6 @@ to which the underlying AWS account has access, regardless of their state.
In addition to all arguments above, the following attributes are exported:

* `names` - A list of the Availability Zone names available to the account.
* `zone_ids` - A list of the Availability Zone IDs available to the account.

Note that the indexes of Availability Zone names and IDs correspond.