-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge #7984: Data sources for AWS and Fastly IP address ranges
- Loading branch information
Showing
11 changed files
with
536 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
package aws | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"io/ioutil" | ||
"log" | ||
"sort" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/hashicorp/go-cleanhttp" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
) | ||
|
||
type dataSourceAwsIPRangesResult struct { | ||
CreateDate string | ||
Prefixes []dataSourceAwsIPRangesPrefix | ||
SyncToken string | ||
} | ||
|
||
type dataSourceAwsIPRangesPrefix struct { | ||
IpPrefix string `json:"ip_prefix"` | ||
Region string | ||
Service string | ||
} | ||
|
||
func dataSourceAwsIPRanges() *schema.Resource { | ||
return &schema.Resource{ | ||
Read: dataSourceAwsIPRangesRead, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"cidr_blocks": &schema.Schema{ | ||
Type: schema.TypeList, | ||
Computed: true, | ||
Elem: &schema.Schema{Type: schema.TypeString}, | ||
}, | ||
"create_date": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"regions": &schema.Schema{ | ||
Type: schema.TypeSet, | ||
Elem: &schema.Schema{Type: schema.TypeString}, | ||
Optional: true, | ||
}, | ||
"services": &schema.Schema{ | ||
Type: schema.TypeSet, | ||
Required: true, | ||
Elem: &schema.Schema{Type: schema.TypeString}, | ||
}, | ||
"sync_token": &schema.Schema{ | ||
Type: schema.TypeInt, | ||
Computed: true, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func dataSourceAwsIPRangesRead(d *schema.ResourceData, meta interface{}) error { | ||
|
||
conn := cleanhttp.DefaultClient() | ||
|
||
log.Printf("[DEBUG] Reading IP ranges") | ||
|
||
res, err := conn.Get("https://ip-ranges.amazonaws.com/ip-ranges.json") | ||
|
||
if err != nil { | ||
return fmt.Errorf("Error listing IP ranges: %s", err) | ||
} | ||
|
||
defer res.Body.Close() | ||
|
||
data, err := ioutil.ReadAll(res.Body) | ||
|
||
if err != nil { | ||
return fmt.Errorf("Error reading response body: %s", err) | ||
} | ||
|
||
result := new(dataSourceAwsIPRangesResult) | ||
|
||
if err := json.Unmarshal(data, result); err != nil { | ||
return fmt.Errorf("Error parsing result: %s", err) | ||
} | ||
|
||
if err := d.Set("create_date", result.CreateDate); err != nil { | ||
return fmt.Errorf("Error setting create date: %s", err) | ||
} | ||
|
||
syncToken, err := strconv.Atoi(result.SyncToken) | ||
|
||
if err != nil { | ||
return fmt.Errorf("Error while converting sync token: %s", err) | ||
} | ||
|
||
d.SetId(result.SyncToken) | ||
|
||
if err := d.Set("sync_token", syncToken); err != nil { | ||
return fmt.Errorf("Error setting sync token: %s", err) | ||
} | ||
|
||
get := func(key string) *schema.Set { | ||
|
||
set := d.Get(key).(*schema.Set) | ||
|
||
for _, e := range set.List() { | ||
|
||
s := e.(string) | ||
|
||
set.Remove(s) | ||
set.Add(strings.ToLower(s)) | ||
|
||
} | ||
|
||
return set | ||
|
||
} | ||
|
||
var ( | ||
regions = get("regions") | ||
services = get("services") | ||
noRegionFilter = regions.Len() == 0 | ||
prefixes []string | ||
) | ||
|
||
for _, e := range result.Prefixes { | ||
|
||
var ( | ||
matchRegion = noRegionFilter || regions.Contains(strings.ToLower(e.Region)) | ||
matchService = services.Contains(strings.ToLower(e.Service)) | ||
) | ||
|
||
if matchRegion && matchService { | ||
prefixes = append(prefixes, e.IpPrefix) | ||
} | ||
|
||
} | ||
|
||
if len(prefixes) == 0 { | ||
return fmt.Errorf(" No IP ranges result from filters") | ||
} | ||
|
||
sort.Strings(prefixes) | ||
|
||
if err := d.Set("cidr_blocks", prefixes); err != nil { | ||
return fmt.Errorf("Error setting ip ranges: %s", err) | ||
} | ||
|
||
return nil | ||
|
||
} |
128 changes: 128 additions & 0 deletions
128
builtin/providers/aws/data_source_aws_ip_ranges_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package aws | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
"regexp" | ||
"sort" | ||
"strconv" | ||
"testing" | ||
"time" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
func TestAccAWSIPRanges(t *testing.T) { | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
resource.TestStep{ | ||
Config: testAccAWSIPRangesConfig, | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccAWSIPRanges("data.aws_ip_ranges.some"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccAWSIPRanges(n string) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
|
||
r := s.RootModule().Resources[n] | ||
a := r.Primary.Attributes | ||
|
||
var ( | ||
cidrBlockSize int | ||
createDate time.Time | ||
err error | ||
syncToken int | ||
) | ||
|
||
if cidrBlockSize, err = strconv.Atoi(a["cidr_blocks.#"]); err != nil { | ||
return err | ||
} | ||
|
||
if cidrBlockSize < 10 { | ||
return fmt.Errorf("cidr_blocks for eu-west-1 seem suspiciously low: %d", cidrBlockSize) | ||
} | ||
|
||
if createDate, err = time.Parse("2006-01-02-15-04-05", a["create_date"]); err != nil { | ||
return err | ||
} | ||
|
||
if syncToken, err = strconv.Atoi(a["sync_token"]); err != nil { | ||
return err | ||
} | ||
|
||
if syncToken != int(createDate.Unix()) { | ||
return fmt.Errorf("sync_token %d does not match create_date %s", syncToken, createDate) | ||
} | ||
|
||
var cidrBlocks sort.StringSlice = make([]string, cidrBlockSize) | ||
|
||
for i := range make([]string, cidrBlockSize) { | ||
|
||
block := a[fmt.Sprintf("cidr_blocks.%d", i)] | ||
|
||
if _, _, err := net.ParseCIDR(block); err != nil { | ||
return fmt.Errorf("malformed CIDR block %s: %s", block, err) | ||
} | ||
|
||
cidrBlocks[i] = block | ||
|
||
} | ||
|
||
if !sort.IsSorted(cidrBlocks) { | ||
return fmt.Errorf("unexpected order of cidr_blocks: %s", cidrBlocks) | ||
} | ||
|
||
var ( | ||
regionMember = regexp.MustCompile(`regions\.\d+`) | ||
regions, services int | ||
serviceMember = regexp.MustCompile(`services\.\d+`) | ||
) | ||
|
||
for k, v := range a { | ||
|
||
if regionMember.MatchString(k) { | ||
|
||
if !(v == "eu-west-1" || v == "EU-central-1") { | ||
return fmt.Errorf("unexpected region %s", v) | ||
} | ||
|
||
regions = regions + 1 | ||
|
||
} | ||
|
||
if serviceMember.MatchString(k) { | ||
|
||
if v != "EC2" { | ||
return fmt.Errorf("unexpected service %s", v) | ||
} | ||
|
||
services = services + 1 | ||
} | ||
|
||
} | ||
|
||
if regions != 2 { | ||
return fmt.Errorf("unexpected number of regions: %d", regions) | ||
} | ||
|
||
if services != 1 { | ||
return fmt.Errorf("unexpected number of services: %d", services) | ||
} | ||
|
||
return nil | ||
} | ||
} | ||
|
||
const testAccAWSIPRangesConfig = ` | ||
data "aws_ip_ranges" "some" { | ||
regions = [ "eu-west-1", "EU-central-1" ] | ||
services = [ "EC2" ] | ||
} | ||
` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package fastly | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"io/ioutil" | ||
"log" | ||
"sort" | ||
"strconv" | ||
|
||
"github.com/hashicorp/go-cleanhttp" | ||
"github.com/hashicorp/terraform/helper/hashcode" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
) | ||
|
||
type dataSourceFastlyIPRangesResult struct { | ||
Addresses []string | ||
} | ||
|
||
func dataSourceFastlyIPRanges() *schema.Resource { | ||
return &schema.Resource{ | ||
Read: dataSourceFastlyIPRangesRead, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"cidr_blocks": &schema.Schema{ | ||
Type: schema.TypeList, | ||
Computed: true, | ||
Elem: &schema.Schema{Type: schema.TypeString}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func dataSourceFastlyIPRangesRead(d *schema.ResourceData, meta interface{}) error { | ||
|
||
conn := cleanhttp.DefaultClient() | ||
|
||
log.Printf("[DEBUG] Reading IP ranges") | ||
|
||
res, err := conn.Get("https://api.fastly.com/public-ip-list") | ||
|
||
if err != nil { | ||
return fmt.Errorf("Error listing IP ranges: %s", err) | ||
} | ||
|
||
defer res.Body.Close() | ||
|
||
data, err := ioutil.ReadAll(res.Body) | ||
|
||
if err != nil { | ||
return fmt.Errorf("Error reading response body: %s", err) | ||
} | ||
|
||
d.SetId(strconv.Itoa(hashcode.String(string(data)))) | ||
|
||
result := new(dataSourceFastlyIPRangesResult) | ||
|
||
if err := json.Unmarshal(data, result); err != nil { | ||
return fmt.Errorf("Error parsing result: %s", err) | ||
} | ||
|
||
sort.Strings(result.Addresses) | ||
|
||
if err := d.Set("cidr_blocks", result.Addresses); err != nil { | ||
return fmt.Errorf("Error setting ip ranges: %s", err) | ||
} | ||
|
||
return nil | ||
|
||
} |
Oops, something went wrong.