provider/aws: availability zone data source
This adds a singular data source in addition to the existing plural one. This allows retrieving data about a specific AZ. As a helper for writing reusable modules, the AZ letter (without its usual region name prefix) is exposed so that it can be used in region-agnostic mappings where a different value is used per AZ, such as for subnet numbering schemes.
This commit is contained in:
parent
aa0b6019f8
commit
fca9216f53
|
@ -0,0 +1,89 @@
|
|||
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 dataSourceAwsAvailabilityZone() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Read: dataSourceAwsAvailabilityZoneRead,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"region": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"name_suffix": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"state": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func dataSourceAwsAvailabilityZoneRead(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
req := &ec2.DescribeAvailabilityZonesInput{}
|
||||
|
||||
if name := d.Get("name"); name != "" {
|
||||
req.ZoneNames = []*string{aws.String(name.(string))}
|
||||
}
|
||||
|
||||
req.Filters = buildEC2AttributeFilterList(
|
||||
map[string]string{
|
||||
"state": d.Get("state").(string),
|
||||
},
|
||||
)
|
||||
if len(req.Filters) == 0 {
|
||||
// Don't send an empty filters list; the EC2 API won't accept it.
|
||||
req.Filters = nil
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] DescribeAvailabilityZones %s\n", req)
|
||||
resp, err := conn.DescribeAvailabilityZones(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp == nil || len(resp.AvailabilityZones) == 0 {
|
||||
return fmt.Errorf("no matching AZ found")
|
||||
}
|
||||
if len(resp.AvailabilityZones) > 1 {
|
||||
return fmt.Errorf("multiple AZs matched; use additional constraints to reduce matches to a single AZ")
|
||||
}
|
||||
|
||||
az := resp.AvailabilityZones[0]
|
||||
|
||||
// As a convenience when working with AZs generically, we expose
|
||||
// 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):]
|
||||
|
||||
d.SetId(*az.ZoneName)
|
||||
d.Set("id", az.ZoneName)
|
||||
d.Set("name", az.ZoneName)
|
||||
d.Set("name_suffix", nameSuffix)
|
||||
d.Set("region", az.RegionName)
|
||||
d.Set("state", az.State)
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccDataSourceAwsAvailabilityZone(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccDataSourceAwsAvailabilityZoneConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccDataSourceAwsAvailabilityZoneCheck("data.aws_availability_zone.by_name"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
data "aws_availability_zone" "by_name" {
|
||||
name = "us-west-2a"
|
||||
}
|
||||
`
|
|
@ -144,6 +144,7 @@ func Provider() terraform.ResourceProvider {
|
|||
|
||||
DataSourcesMap: map[string]*schema.Resource{
|
||||
"aws_ami": dataSourceAwsAmi(),
|
||||
"aws_availability_zone": dataSourceAwsAvailabilityZone(),
|
||||
"aws_availability_zones": dataSourceAwsAvailabilityZones(),
|
||||
"aws_caller_identity": dataSourceAwsCallerIdentity(),
|
||||
"aws_cloudformation_stack": dataSourceAwsCloudFormationStack(),
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
---
|
||||
layout: "aws"
|
||||
page_title: "AWS: aws_availability_zone"
|
||||
sidebar_current: "docs-aws-datasource-availability-zone"
|
||||
description: |-
|
||||
Provides details about a specific availability zone
|
||||
---
|
||||
|
||||
# aws\_availability\_zone
|
||||
|
||||
`aws_availability_zone` provides details about a specific availablity zone (AZ)
|
||||
in the current region.
|
||||
|
||||
This can be used both to validate an availability zone given in a variable
|
||||
and to split the AZ name into its component parts of an AWS region and an
|
||||
AZ identifier letter. The latter may be useful e.g. for implementing a
|
||||
consistent subnet numbering scheme across several regions by mapping both
|
||||
the region and the subnet letter to network numbers.
|
||||
|
||||
This is different from the `aws_availability_zones` (plural) data source,
|
||||
which provides a list of the available zones.
|
||||
|
||||
## Example Usage
|
||||
|
||||
The following example shows how this data source might be used to derive
|
||||
VPC and subnet CIDR prefixes systematically for an availability zone.
|
||||
|
||||
```
|
||||
variable "region_number" {
|
||||
# Arbitrary mapping of region name to number to use in
|
||||
# a VPC's CIDR prefix.
|
||||
default = {
|
||||
us-east-1 = 1
|
||||
us-west-1 = 2
|
||||
us-west-2 = 3
|
||||
eu-central-1 = 4
|
||||
ap-northeast-1 = 5
|
||||
}
|
||||
}
|
||||
|
||||
variable "az_number" {
|
||||
# Assign a number to each AZ letter used in our configuration
|
||||
default = {
|
||||
a = 1
|
||||
b = 2
|
||||
c = 3
|
||||
d = 4
|
||||
e = 5
|
||||
f = 6
|
||||
}
|
||||
}
|
||||
|
||||
# Retrieve the AZ where we want to create network resources
|
||||
# This must be in the region selected on the AWS provider.
|
||||
data "aws_availability_zone" "example" {
|
||||
name = "eu-central-1a"
|
||||
}
|
||||
|
||||
# Create a VPC for the region associated with the AZ
|
||||
resource "aws_vpc" "example" {
|
||||
cidr_block = "${cidrsubnet("10.0.0.0/8", 4, var.region_number[data.aws_availability_zone.example.region])}"
|
||||
}
|
||||
|
||||
# Create a subnet for the AZ within the regional VPC
|
||||
resource "aws_subnet" "example" {
|
||||
vpc_id = "${aws_vpc.example.id}"
|
||||
cidr_block = "${cidrsubnet(aws_vpc.example.cidr_block, 4, var.az_number[data.aws_availability_zone.name_suffix])}"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The arguments of this data source act as filters for querying the available
|
||||
availability zones. The given filters must match exactly one availability
|
||||
zone whose data will be exported as attributes.
|
||||
|
||||
* `name` - (Optional) The full name of the availability zone to select.
|
||||
|
||||
* `state` - (Optional) A specific availability zone state to require. May
|
||||
be any of `"available"`, `"information"`, `"impaired"` or `"available"`.
|
||||
|
||||
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.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `name` - The name of the selected availability zone.
|
||||
|
||||
* `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.
|
||||
|
||||
* `name_suffix` - The part of the AZ name that appears after the region name,
|
||||
uniquely identifying the AZ within its region.
|
||||
|
||||
* `state` - The current state of the AZ.
|
|
@ -12,6 +12,9 @@ The Availability Zones data source allows access to the list of AWS
|
|||
Availability Zones which can be accessed by an AWS account within the region
|
||||
configured in the provider.
|
||||
|
||||
This is different from the `aws_availability_zone` (singular) data source,
|
||||
which provides some details about a specific availability zone.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
<li<%= sidebar_current("docs-aws-datasource-ami") %>>
|
||||
<a href="/docs/providers/aws/d/ami.html">aws_ami</a>
|
||||
</li>
|
||||
<li<%= sidebar_current("docs-aws-datasource-availability-zone") %>>
|
||||
<a href="/docs/providers/aws/d/availability_zone.html">aws_availability_zone</a>
|
||||
</li>
|
||||
<li<%= sidebar_current("docs-aws-datasource-availability-zones") %>>
|
||||
<a href="/docs/providers/aws/d/availability_zones.html">aws_availability_zones</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue