Skip to content

Commit

Permalink
service/ec2: Initial support for Local Zones
Browse files Browse the repository at this point in the history
Reference: #11136
Reference: #11994

Changes:

* New Resource: `aws_ec2_availability_zone_group`
* data-source/aws_availability_zone: Add `all_availability_zones` and `filter` arguments
* data-source/aws_availability_zone: Add `group_name`, `network_border_group`, and `opt_in_status` attributes
* data-source/aws_availability_zones: Add `all_availability_zones` and `filter` arguments
* data-source/aws_availability_zones: Add `group_names` attribute

```
--- PASS: TestAccDataSourceAwsAvailabilityZone_Filter (17.53s)
--- PASS: TestAccDataSourceAwsAvailabilityZone_ZoneId (17.74s)
--- PASS: TestAccDataSourceAwsAvailabilityZone_AllAvailabilityZones (17.74s)
--- PASS: TestAccDataSourceAwsAvailabilityZone_Name (17.79s)

--- PASS: TestAccAWSAvailabilityZones_Filter (15.46s)
--- PASS: TestAccAWSAvailabilityZones_stateFilter (15.87s)
--- PASS: TestAccAWSAvailabilityZones_basic (16.60s)
--- PASS: TestAccAWSAvailabilityZones_AllAvailabilityZones (16.70s)
--- PASS: TestAccAWSAvailabilityZones_BlacklistedNames (17.00s)
--- PASS: TestAccAWSAvailabilityZones_BlacklistedZoneIds (17.14s)

--- PASS: TestAccAWSEc2AvailabilityZoneGroup_OptInStatus (37.67s)
```
  • Loading branch information
bflad committed Mar 15, 2020
1 parent 04d24f8 commit 7324d48
Show file tree
Hide file tree
Showing 11 changed files with 636 additions and 42 deletions.
39 changes: 33 additions & 6 deletions aws/data_source_aws_availability_zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,41 @@ func dataSourceAwsAvailabilityZone() *schema.Resource {
Read: dataSourceAwsAvailabilityZoneRead,

Schema: map[string]*schema.Schema{
"all_availability_zones": {
Type: schema.TypeBool,
Optional: true,
},
"filter": ec2CustomFiltersSchema(),
"group_name": {
Type: schema.TypeString,
Computed: true,
},
"name": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},

"region": {
"name_suffix": {
Type: schema.TypeString,
Computed: true,
},

"name_suffix": {
"network_border_group": {
Type: schema.TypeString,
Computed: true,
},
"opt_in_status": {
Type: schema.TypeString,
Computed: true,
},
"region": {
Type: schema.TypeString,
Computed: true,
},

"state": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},

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

req := &ec2.DescribeAvailabilityZonesInput{}

if v, ok := d.GetOk("all_availability_zones"); ok {
req.AllAvailabilityZones = aws.Bool(v.(bool))
}

if v := d.Get("name").(string); v != "" {
req.ZoneNames = []*string{aws.String(v)}
}
Expand All @@ -61,6 +78,13 @@ func dataSourceAwsAvailabilityZoneRead(d *schema.ResourceData, meta interface{})
"state": d.Get("state").(string),
},
)

if filters, filtersOk := d.GetOk("filter"); filtersOk {
req.Filters = append(req.Filters, buildEC2CustomFilterList(
filters.(*schema.Set),
)...)
}

if len(req.Filters) == 0 {
// Don't send an empty filters list; the EC2 API won't accept it.
req.Filters = nil
Expand All @@ -87,8 +111,11 @@ func dataSourceAwsAvailabilityZoneRead(d *schema.ResourceData, meta interface{})
nameSuffix := (*az.ZoneName)[len(*az.RegionName):]

d.SetId(aws.StringValue(az.ZoneName))
d.Set("group_name", az.GroupName)
d.Set("name", az.ZoneName)
d.Set("name_suffix", nameSuffix)
d.Set("network_border_group", az.NetworkBorderGroup)
d.Set("opt_in_status", az.OptInStatus)
d.Set("region", az.RegionName)
d.Set("state", az.State)
d.Set("zone_id", az.ZoneId)
Expand Down
144 changes: 125 additions & 19 deletions aws/data_source_aws_availability_zone_test.go
Original file line number Diff line number Diff line change
@@ -1,43 +1,149 @@
package aws

import (
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)

func TestAccDataSourceAwsAvailabilityZone(t *testing.T) {
ds1ResourceName := "data.aws_availability_zone.by_name"
ds2ResourceName := "data.aws_availability_zone.by_zone_id"
func TestAccDataSourceAwsAvailabilityZone_AllAvailabilityZones(t *testing.T) {
availabilityZonesDataSourceName := "data.aws_availability_zones.test"
dataSourceName := "data.aws_availability_zone.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAwsAvailabilityZoneConfig,
Config: testAccDataSourceAwsAvailabilityZoneConfigAllAvailabilityZones(),
Check: resource.ComposeTestCheckFunc(
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"),
resource.TestCheckResourceAttr(dataSourceName, "group_name", testAccGetRegion()),
resource.TestCheckResourceAttrPair(dataSourceName, "name", availabilityZonesDataSourceName, "names.0"),
resource.TestMatchResourceAttr(dataSourceName, "name_suffix", regexp.MustCompile(`^[a-z]$`)),
resource.TestCheckResourceAttr(dataSourceName, "network_border_group", testAccGetRegion()),
resource.TestCheckResourceAttr(dataSourceName, "opt_in_status", "opt-in-not-required"),
resource.TestCheckResourceAttr(dataSourceName, "region", testAccGetRegion()),
resource.TestCheckResourceAttrPair(dataSourceName, "zone_id", availabilityZonesDataSourceName, "zone_ids.0"),
),
},
},
})
}

const testAccDataSourceAwsAvailabilityZoneConfig = `
data "aws_availability_zone" "by_name" {
name = "us-west-2a"
func TestAccDataSourceAwsAvailabilityZone_Filter(t *testing.T) {
availabilityZonesDataSourceName := "data.aws_availability_zones.test"
dataSourceName := "data.aws_availability_zone.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAwsAvailabilityZoneConfigFilter(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceName, "group_name", testAccGetRegion()),
resource.TestCheckResourceAttrPair(dataSourceName, "name", availabilityZonesDataSourceName, "names.0"),
resource.TestMatchResourceAttr(dataSourceName, "name_suffix", regexp.MustCompile(`^[a-z]$`)),
resource.TestCheckResourceAttr(dataSourceName, "network_border_group", testAccGetRegion()),
resource.TestCheckResourceAttr(dataSourceName, "opt_in_status", "opt-in-not-required"),
resource.TestCheckResourceAttr(dataSourceName, "region", testAccGetRegion()),
resource.TestCheckResourceAttrPair(dataSourceName, "zone_id", availabilityZonesDataSourceName, "zone_ids.0"),
),
},
},
})
}

func TestAccDataSourceAwsAvailabilityZone_Name(t *testing.T) {
availabilityZonesDataSourceName := "data.aws_availability_zones.test"
dataSourceName := "data.aws_availability_zone.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAwsAvailabilityZoneConfigName(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceName, "group_name", testAccGetRegion()),
resource.TestCheckResourceAttrPair(dataSourceName, "name", availabilityZonesDataSourceName, "names.0"),
resource.TestMatchResourceAttr(dataSourceName, "name_suffix", regexp.MustCompile(`^[a-z]$`)),
resource.TestCheckResourceAttr(dataSourceName, "network_border_group", testAccGetRegion()),
resource.TestCheckResourceAttr(dataSourceName, "opt_in_status", "opt-in-not-required"),
resource.TestCheckResourceAttr(dataSourceName, "region", testAccGetRegion()),
resource.TestCheckResourceAttrPair(dataSourceName, "zone_id", availabilityZonesDataSourceName, "zone_ids.0"),
),
},
},
})
}

data "aws_availability_zone" "by_zone_id" {
zone_id = "${data.aws_availability_zone.by_name.zone_id}"
func TestAccDataSourceAwsAvailabilityZone_ZoneId(t *testing.T) {
availabilityZonesDataSourceName := "data.aws_availability_zones.test"
dataSourceName := "data.aws_availability_zone.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAwsAvailabilityZoneConfigZoneId(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(dataSourceName, "group_name", testAccGetRegion()),
resource.TestCheckResourceAttrPair(dataSourceName, "name", availabilityZonesDataSourceName, "names.0"),
resource.TestMatchResourceAttr(dataSourceName, "name_suffix", regexp.MustCompile(`^[a-z]$`)),
resource.TestCheckResourceAttr(dataSourceName, "network_border_group", testAccGetRegion()),
resource.TestCheckResourceAttr(dataSourceName, "opt_in_status", "opt-in-not-required"),
resource.TestCheckResourceAttr(dataSourceName, "region", testAccGetRegion()),
resource.TestCheckResourceAttrPair(dataSourceName, "zone_id", availabilityZonesDataSourceName, "zone_ids.0"),
),
},
},
})
}

func testAccDataSourceAwsAvailabilityZoneConfigAllAvailabilityZones() string {
return fmt.Sprintf(`
data "aws_availability_zones" "test" {}
data "aws_availability_zone" "test" {
all_availability_zones = true
name = data.aws_availability_zones.test.names[0]
}
`)
}

func testAccDataSourceAwsAvailabilityZoneConfigFilter() string {
return fmt.Sprintf(`
data "aws_availability_zones" "test" {}
data "aws_availability_zone" "test" {
filter {
name = "zone-name"
values = [data.aws_availability_zones.test.names[0]]
}
}
`)
}

func testAccDataSourceAwsAvailabilityZoneConfigName() string {
return fmt.Sprintf(`
data "aws_availability_zones" "test" {}
data "aws_availability_zone" "test" {
name = data.aws_availability_zones.test.names[0]
}
`)
}

func testAccDataSourceAwsAvailabilityZoneConfigZoneId() string {
return fmt.Sprintf(`
data "aws_availability_zones" "test" {}
data "aws_availability_zone" "test" {
zone_id = data.aws_availability_zones.test.zone_ids[0]
}
`)
}
`
34 changes: 34 additions & 0 deletions aws/data_source_aws_availability_zones.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ func dataSourceAwsAvailabilityZones() *schema.Resource {
Read: dataSourceAwsAvailabilityZonesRead,

Schema: map[string]*schema.Schema{
"all_availability_zones": {
Type: schema.TypeBool,
Optional: true,
},
"blacklisted_names": {
Type: schema.TypeSet,
Optional: true,
Expand All @@ -27,6 +31,12 @@ func dataSourceAwsAvailabilityZones() *schema.Resource {
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"filter": ec2CustomFiltersSchema(),
"group_names": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"names": {
Type: schema.TypeList,
Computed: true,
Expand Down Expand Up @@ -59,6 +69,10 @@ func dataSourceAwsAvailabilityZonesRead(d *schema.ResourceData, meta interface{}

request := &ec2.DescribeAvailabilityZonesInput{}

if v, ok := d.GetOk("all_availability_zones"); ok {
request.AllAvailabilityZones = aws.Bool(v.(bool))
}

if v, ok := d.GetOk("state"); ok {
request.Filters = []*ec2.Filter{
{
Expand All @@ -68,6 +82,17 @@ func dataSourceAwsAvailabilityZonesRead(d *schema.ResourceData, meta interface{}
}
}

if filters, filtersOk := d.GetOk("filter"); filtersOk {
request.Filters = append(request.Filters, buildEC2CustomFilterList(
filters.(*schema.Set),
)...)
}

if len(request.Filters) == 0 {
// Don't send an empty filters list; the EC2 API won't accept it.
request.Filters = nil
}

log.Printf("[DEBUG] Reading Availability Zones: %s", request)
resp, err := conn.DescribeAvailabilityZones(request)
if err != nil {
Expand All @@ -80,9 +105,11 @@ func dataSourceAwsAvailabilityZonesRead(d *schema.ResourceData, meta interface{}

blacklistedNames := d.Get("blacklisted_names").(*schema.Set)
blacklistedZoneIDs := d.Get("blacklisted_zone_ids").(*schema.Set)
groupNames := schema.NewSet(schema.HashString, nil)
names := []string{}
zoneIds := []string{}
for _, v := range resp.AvailabilityZones {
groupName := aws.StringValue(v.GroupName)
name := aws.StringValue(v.ZoneName)
zoneID := aws.StringValue(v.ZoneId)

Expand All @@ -94,10 +121,17 @@ func dataSourceAwsAvailabilityZonesRead(d *schema.ResourceData, meta interface{}
continue
}

if !groupNames.Contains(groupName) {
groupNames.Add(groupName)
}

names = append(names, name)
zoneIds = append(zoneIds, zoneID)
}

if err := d.Set("group_names", groupNames); err != nil {
return fmt.Errorf("error setting group_names: %s", err)
}
if err := d.Set("names", names); err != nil {
return fmt.Errorf("Error setting Availability Zone names: %s", err)
}
Expand Down
Loading

0 comments on commit 7324d48

Please sign in to comment.