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{
|
DataSourcesMap: map[string]*schema.Resource{
|
||||||
"aws_ami": dataSourceAwsAmi(),
|
"aws_ami": dataSourceAwsAmi(),
|
||||||
|
"aws_availability_zone": dataSourceAwsAvailabilityZone(),
|
||||||
"aws_availability_zones": dataSourceAwsAvailabilityZones(),
|
"aws_availability_zones": dataSourceAwsAvailabilityZones(),
|
||||||
"aws_caller_identity": dataSourceAwsCallerIdentity(),
|
"aws_caller_identity": dataSourceAwsCallerIdentity(),
|
||||||
"aws_cloudformation_stack": dataSourceAwsCloudFormationStack(),
|
"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
|
Availability Zones which can be accessed by an AWS account within the region
|
||||||
configured in the provider.
|
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
|
## Example Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
<li<%= sidebar_current("docs-aws-datasource-ami") %>>
|
<li<%= sidebar_current("docs-aws-datasource-ami") %>>
|
||||||
<a href="/docs/providers/aws/d/ami.html">aws_ami</a>
|
<a href="/docs/providers/aws/d/ami.html">aws_ami</a>
|
||||||
</li>
|
</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") %>>
|
<li<%= sidebar_current("docs-aws-datasource-availability-zones") %>>
|
||||||
<a href="/docs/providers/aws/d/availability_zones.html">aws_availability_zones</a>
|
<a href="/docs/providers/aws/d/availability_zones.html">aws_availability_zones</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
Loading…
Reference in New Issue