diff --git a/builtin/providers/aws/data_source_availability_zones.go b/builtin/providers/aws/data_source_availability_zones.go index fd3a6f18a..a9a9d501f 100644 --- a/builtin/providers/aws/data_source_availability_zones.go +++ b/builtin/providers/aws/data_source_availability_zones.go @@ -21,6 +21,11 @@ func dataSourceAwsAvailabilityZones() *schema.Resource { Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + "state": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateStateType, + }, }, } } @@ -28,25 +33,55 @@ func dataSourceAwsAvailabilityZones() *schema.Resource { func dataSourceAwsAvailabilityZonesRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - log.Printf("[DEBUG] Reading availability zones") + log.Printf("[DEBUG] Reading Availability Zones.") d.SetId(time.Now().UTC().String()) - req := &ec2.DescribeAvailabilityZonesInput{DryRun: aws.Bool(false)} - azresp, err := conn.DescribeAvailabilityZones(req) - if err != nil { - return fmt.Errorf("Error listing availability zones: %s", err) + request := &ec2.DescribeAvailabilityZonesInput{} + + if v, ok := d.GetOk("state"); ok { + request.Filters = []*ec2.Filter{ + &ec2.Filter{ + Name: aws.String("state"), + Values: []*string{aws.String(v.(string))}, + }, + } } - raw := make([]string, len(azresp.AvailabilityZones)) - for i, v := range azresp.AvailabilityZones { + log.Printf("[DEBUG] Availability Zones request options: %#v", *request) + + resp, err := conn.DescribeAvailabilityZones(request) + if err != nil { + 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 } sort.Strings(raw) if err := d.Set("names", raw); err != nil { - return fmt.Errorf("[WARN] Error setting availability zones") + return fmt.Errorf("[WARN] Error setting Availability Zones: %s", err) } return nil } + +func validateStateType(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + + validState := map[string]bool{ + "available": true, + "information": true, + "impaired": true, + "unavailable": true, + } + + if !validState[value] { + errors = append(errors, fmt.Errorf( + "%q contains an invalid Availability Zone state %q. Valid states are: %q, %q, %q and %q.", + k, value, "available", "information", "impaired", "unavailable")) + } + return +} diff --git a/builtin/providers/aws/data_source_availability_zones_test.go b/builtin/providers/aws/data_source_availability_zones_test.go index 86060fb8f..7dbae2398 100644 --- a/builtin/providers/aws/data_source_availability_zones_test.go +++ b/builtin/providers/aws/data_source_availability_zones_test.go @@ -22,6 +22,12 @@ func TestAccAWSAvailabilityZones_basic(t *testing.T) { testAccCheckAwsAvailabilityZonesMeta("data.aws_availability_zones.availability_zones"), ), }, + resource.TestStep{ + Config: testAccCheckAwsAvailabilityZonesStateConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsAvailabilityZoneState("data.aws_availability_zones.state_filter"), + ), + }, }, }) } @@ -34,7 +40,7 @@ func testAccCheckAwsAvailabilityZonesMeta(n string) resource.TestCheckFunc { } if rs.Primary.ID == "" { - return fmt.Errorf("AZ resource ID not set") + return fmt.Errorf("AZ resource ID not set.") } actual, err := testAccCheckAwsAvailabilityZonesBuildAvailable(rs.Primary.Attributes) @@ -51,10 +57,33 @@ func testAccCheckAwsAvailabilityZonesMeta(n string) resource.TestCheckFunc { } } +func testAccCheckAwsAvailabilityZoneState(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Can't find AZ resource: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("AZ resource ID not set.") + } + + if _, ok := rs.Primary.Attributes["state"]; !ok { + return fmt.Errorf("AZs state filter is missing, should be set.") + } + + _, err := testAccCheckAwsAvailabilityZonesBuildAvailable(rs.Primary.Attributes) + if err != nil { + return err + } + return nil + } +} + 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 list is missing.") } qty, err := strconv.Atoi(v) if err != nil { @@ -67,7 +96,7 @@ func testAccCheckAwsAvailabilityZonesBuildAvailable(attrs map[string]string) ([] for n := range zones { zone, ok := attrs["names."+strconv.Itoa(n)] if !ok { - return nil, fmt.Errorf("AZ list corrupt, this is definitely a bug") + return nil, fmt.Errorf("AZ list corrupt, this is definitely a bug.") } zones[n] = zone } @@ -75,6 +104,11 @@ func testAccCheckAwsAvailabilityZonesBuildAvailable(attrs map[string]string) ([] } const testAccCheckAwsAvailabilityZonesConfig = ` -data "aws_availability_zones" "availability_zones" { +data "aws_availability_zones" "availability_zones" { } +` + +const testAccCheckAwsAvailabilityZonesStateConfig = ` +data "aws_availability_zones" "state_filter" { + state = "available" } ` diff --git a/website/source/docs/providers/aws/d/availability_zones.html.markdown b/website/source/docs/providers/aws/d/availability_zones.html.markdown index e482a142b..0eb87d781 100644 --- a/website/source/docs/providers/aws/d/availability_zones.html.markdown +++ b/website/source/docs/providers/aws/d/availability_zones.html.markdown @@ -3,7 +3,7 @@ layout: "aws" page_title: "AWS: aws_availability_zones" sidebar_current: "docs-aws-datasource-availability-zones" description: |- - Provides a list of availability zones which can be used by an AWS account + Provides a list of Availability Zones which can be used by an AWS account. --- # aws\_availability\_zones @@ -35,10 +35,15 @@ resource "aws_subnet" "secondary" { ## Argument Reference -There are no arguments for this data source. +The following arguments are supported: + +* `state` - (Optional) Allows to filter list of Availability Zones based on their +current state. Can be either `"available"`, `"information"`, `"impaired"` or +`"unavailable"`. By default the list includes a complete set of Availability Zones +to which the underlying AWS account has access, regardless of their state. ## Attributes Reference The following attributes are exported: -* `names` - A list of the availability zone names available to the account. +* `names` - A list of the Availability Zone names available to the account.