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

d/aws_availability_zone: Additional attributes for Local and Wavelength Zones #16770

Merged
merged 5 commits into from
Dec 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
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
20 changes: 19 additions & 1 deletion aws/data_source_aws_availability_zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package aws
import (
"fmt"
"log"
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
Expand Down Expand Up @@ -40,6 +41,14 @@ func dataSourceAwsAvailabilityZone() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"parent_zone_id": {
Type: schema.TypeString,
Computed: true,
},
"parent_zone_name": {
Type: schema.TypeString,
Computed: true,
},
"region": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -54,6 +63,10 @@ func dataSourceAwsAvailabilityZone() *schema.Resource {
Optional: true,
Computed: true,
},
"zone_type": {
Type: schema.TypeString,
Computed: true,
},
},
}
}
Expand Down Expand Up @@ -108,17 +121,22 @@ func dataSourceAwsAvailabilityZoneRead(d *schema.ResourceData, meta interface{})
// the AZ suffix alone, without the region name.
// This can be used e.g. to create lookup tables by AZ letter that
// work regardless of region.
nameSuffix := (*az.ZoneName)[len(*az.RegionName):]
nameSuffix := aws.StringValue(az.ZoneName)[len(aws.StringValue(az.RegionName)):]
// For Local and Wavelength zones, remove any leading "-".
nameSuffix = strings.TrimLeft(nameSuffix, "-")

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("parent_zone_id", az.ParentZoneId)
d.Set("parent_zone_name", az.ParentZoneName)
d.Set("region", az.RegionName)
d.Set("state", az.State)
d.Set("zone_id", az.ZoneId)
d.Set("zone_type", az.ZoneType)

return nil
}
147 changes: 135 additions & 12 deletions aws/data_source_aws_availability_zone_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package aws

import (
"fmt"
"regexp"
"testing"

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

Expand All @@ -22,9 +24,12 @@ func TestAccDataSourceAwsAvailabilityZone_AllAvailabilityZones(t *testing.T) {
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, "opt_in_status", ec2.AvailabilityZoneOptInStatusOptInNotRequired),
resource.TestCheckResourceAttr(dataSourceName, "parent_zone_id", ""),
resource.TestCheckResourceAttr(dataSourceName, "parent_zone_name", ""),
resource.TestCheckResourceAttr(dataSourceName, "region", testAccGetRegion()),
resource.TestCheckResourceAttrPair(dataSourceName, "zone_id", availabilityZonesDataSourceName, "zone_ids.0"),
resource.TestCheckResourceAttr(dataSourceName, "zone_type", "availability-zone"),
),
},
},
Expand All @@ -46,9 +51,39 @@ func TestAccDataSourceAwsAvailabilityZone_Filter(t *testing.T) {
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, "opt_in_status", ec2.AvailabilityZoneOptInStatusOptInNotRequired),
resource.TestCheckResourceAttr(dataSourceName, "parent_zone_id", ""),
resource.TestCheckResourceAttr(dataSourceName, "parent_zone_name", ""),
resource.TestCheckResourceAttr(dataSourceName, "region", testAccGetRegion()),
resource.TestCheckResourceAttrPair(dataSourceName, "zone_id", availabilityZonesDataSourceName, "zone_ids.0"),
resource.TestCheckResourceAttr(dataSourceName, "zone_type", "availability-zone"),
),
},
},
})
}

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

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSLocalZoneAvailable(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAwsAvailabilityZoneConfigZoneType("local-zone"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(dataSourceName, "group_name"),
resource.TestCheckResourceAttrPair(dataSourceName, "name", availabilityZonesDataSourceName, "names.0"),
resource.TestMatchResourceAttr(dataSourceName, "name_suffix", regexp.MustCompile(`^[a-z0-9][a-z0-9-]+$`)),
resource.TestCheckResourceAttrSet(dataSourceName, "network_border_group"),
resource.TestCheckResourceAttr(dataSourceName, "opt_in_status", ec2.AvailabilityZoneOptInStatusOptedIn),
resource.TestCheckResourceAttrSet(dataSourceName, "parent_zone_id"),
resource.TestCheckResourceAttrSet(dataSourceName, "parent_zone_name"),
resource.TestCheckResourceAttr(dataSourceName, "region", testAccGetRegion()),
resource.TestCheckResourceAttrPair(dataSourceName, "zone_id", availabilityZonesDataSourceName, "zone_ids.0"),
resource.TestCheckResourceAttr(dataSourceName, "zone_type", "local-zone"),
),
},
},
Expand All @@ -70,9 +105,39 @@ func TestAccDataSourceAwsAvailabilityZone_Name(t *testing.T) {
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, "opt_in_status", ec2.AvailabilityZoneOptInStatusOptInNotRequired),
resource.TestCheckResourceAttr(dataSourceName, "parent_zone_id", ""),
resource.TestCheckResourceAttr(dataSourceName, "parent_zone_name", ""),
resource.TestCheckResourceAttr(dataSourceName, "region", testAccGetRegion()),
resource.TestCheckResourceAttrPair(dataSourceName, "zone_id", availabilityZonesDataSourceName, "zone_ids.0"),
resource.TestCheckResourceAttr(dataSourceName, "zone_type", "availability-zone"),
),
},
},
})
}

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

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWavelengthZoneAvailable(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAwsAvailabilityZoneConfigZoneType("wavelength-zone"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(dataSourceName, "group_name"),
resource.TestCheckResourceAttrPair(dataSourceName, "name", availabilityZonesDataSourceName, "names.0"),
resource.TestMatchResourceAttr(dataSourceName, "name_suffix", regexp.MustCompile(`^[a-z0-9][a-z0-9-]+$`)),
resource.TestCheckResourceAttrSet(dataSourceName, "network_border_group"),
resource.TestCheckResourceAttr(dataSourceName, "opt_in_status", ec2.AvailabilityZoneOptInStatusOptedIn),
resource.TestCheckResourceAttrSet(dataSourceName, "parent_zone_id"),
resource.TestCheckResourceAttrSet(dataSourceName, "parent_zone_name"),
resource.TestCheckResourceAttr(dataSourceName, "region", testAccGetRegion()),
resource.TestCheckResourceAttrPair(dataSourceName, "zone_id", availabilityZonesDataSourceName, "zone_ids.0"),
resource.TestCheckResourceAttr(dataSourceName, "zone_type", "wavelength-zone"),
),
},
},
Expand All @@ -94,47 +159,105 @@ func TestAccDataSourceAwsAvailabilityZone_ZoneId(t *testing.T) {
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, "opt_in_status", ec2.AvailabilityZoneOptInStatusOptInNotRequired),
resource.TestCheckResourceAttr(dataSourceName, "parent_zone_id", ""),
resource.TestCheckResourceAttr(dataSourceName, "parent_zone_name", ""),
resource.TestCheckResourceAttr(dataSourceName, "region", testAccGetRegion()),
resource.TestCheckResourceAttrPair(dataSourceName, "zone_id", availabilityZonesDataSourceName, "zone_ids.0"),
resource.TestCheckResourceAttr(dataSourceName, "zone_type", "availability-zone"),
),
},
},
})
}

func testAccPreCheckAWSLocalZoneAvailable(t *testing.T) {
conn := testAccProvider.Meta().(*AWSClient).ec2conn

input := &ec2.DescribeAvailabilityZonesInput{
Filters: buildEC2AttributeFilterList(map[string]string{
"zone-type": "local-zone",
"opt-in-status": "opted-in",
}),
}

output, err := conn.DescribeAvailabilityZones(input)

if testAccPreCheckSkipError(err) {
t.Skipf("skipping acceptance testing: %s", err)
}

if err != nil {
t.Fatalf("unexpected PreCheck error: %s", err)
}

if output == nil || len(output.AvailabilityZones) == 0 {
t.Skip("skipping since no Local Zones are available")
}
}

func testAccDataSourceAwsAvailabilityZoneConfigAllAvailabilityZones() string {
return testAccAvailableAZsNoOptInConfig() + `
return composeConfig(
testAccAvailableAZsNoOptInConfig(),
`
data "aws_availability_zone" "test" {
all_availability_zones = true
name = data.aws_availability_zones.available.names[0]
}
`
`)
}

func testAccDataSourceAwsAvailabilityZoneConfigFilter() string {
return testAccAvailableAZsNoOptInConfig() + `
return composeConfig(
testAccAvailableAZsNoOptInConfig(),
`
data "aws_availability_zone" "test" {
filter {
name = "zone-name"
values = [data.aws_availability_zones.available.names[0]]
}
}
`
`)
}

func testAccDataSourceAwsAvailabilityZoneConfigName() string {
return testAccAvailableAZsNoOptInConfig() + `
return composeConfig(
testAccAvailableAZsNoOptInConfig(),
`
data "aws_availability_zone" "test" {
name = data.aws_availability_zones.available.names[0]
}
`
`)
}

func testAccDataSourceAwsAvailabilityZoneConfigZoneId() string {
return testAccAvailableAZsNoOptInConfig() + `
return composeConfig(
testAccAvailableAZsNoOptInConfig(),
`
data "aws_availability_zone" "test" {
zone_id = data.aws_availability_zones.available.zone_ids[0]
}
`)
}

func testAccDataSourceAwsAvailabilityZoneConfigZoneType(zoneType string) string {
return fmt.Sprintf(`
data "aws_availability_zones" "available" {
state = "available"

filter {
name = "zone-type"
values = [%[1]q]
}

filter {
name = "opt-in-status"
values = ["opted-in"]
}
}

data "aws_availability_zone" "test" {
zone_id = data.aws_availability_zones.available.zone_ids[0]
}
`
`, zoneType)
}
5 changes: 5 additions & 0 deletions website/docs/d/availability_zone.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ In addition to all arguments above, the following attributes are exported:

* `group_name` - For Availability Zones, this is the same value as the Region name. For Local Zones, the name of the associated group, for example `us-west-2-lax-1`.
* `name_suffix` - The part of the AZ name that appears after the region name, uniquely identifying the AZ within its region.
For Availability Zones this is usually a single letter, for example `a` for the `us-west-2a` zone.
For Local and Wavelength Zones this is a longer string, for example `wl1-sfo-wlz-1` for the `us-west-2-wl1-sfo-wlz-1` zone.
* `network_border_group` - The name of the location from which the address is advertised.
* `opt_in_status` - For Availability Zones, this always has the value of `opt-in-not-required`. For Local Zones, this is the opt in status. The possible values are `opted-in` and `not-opted-in`.
* `parent_zone_id` - The ID of the zone that handles some of the Local Zone or Wavelength Zone control plane operations, such as API calls.
* `parent_zone_name` - The name of the zone that handles some of the Local Zone or Wavelength Zone control plane operations, such as API calls.
* `region` - The region where the selected availability zone resides. This is always the region selected on the provider, since this data source searches only within that region.
* `zone_type` - The type of zone. Values are `availability-zone`, `local-zone`, and `wavelength-zone`.