Merge branch 'master' of https://github.com/GiovanniPaoloGibilisco/terraform
This commit is contained in:
commit
7bb7508c86
|
@ -6,6 +6,8 @@ FEATURES:
|
||||||
* **New Resource:** `aws_load_balancer_policy` [GH-7458]
|
* **New Resource:** `aws_load_balancer_policy` [GH-7458]
|
||||||
* **New Resource:** `aws_load_balancer_backend_server_policy` [GH-7458]
|
* **New Resource:** `aws_load_balancer_backend_server_policy` [GH-7458]
|
||||||
* **New Resource:** `aws_load_balancer_listener_policy` [GH-7458]
|
* **New Resource:** `aws_load_balancer_listener_policy` [GH-7458]
|
||||||
|
* **New Data Source:** `aws_ip_ranges` [GH-7984]
|
||||||
|
* **New Data Source:** `fastly_ip_ranges` [GH-7984]
|
||||||
|
|
||||||
IMPROVEMENTS
|
IMPROVEMENTS
|
||||||
* provider/aws: Introduce `aws_elasticsearch_domain` `elasticsearch_version` field (to specify ES version) [GH-7860]
|
* provider/aws: Introduce `aws_elasticsearch_domain` `elasticsearch_version` field (to specify ES version) [GH-7860]
|
||||||
|
@ -14,6 +16,8 @@ IMPROVEMENTS
|
||||||
* provider/aws: Add support for Elasticsearch destination to firehose delivery streams [GH-7839]
|
* provider/aws: Add support for Elasticsearch destination to firehose delivery streams [GH-7839]
|
||||||
* provider/aws: Retry AttachInternetGateway and increase timeout on `aws_internet_gateway` [GH-7891]
|
* provider/aws: Retry AttachInternetGateway and increase timeout on `aws_internet_gateway` [GH-7891]
|
||||||
* provider/aws: Add support for Enhanced monitoring to `aws_rds_cluster_instance` [GH-8038]
|
* provider/aws: Add support for Enhanced monitoring to `aws_rds_cluster_instance` [GH-8038]
|
||||||
|
* provider/aws: Add ability to set Requests Payer in `aws_s3_bucket` [GH-8065]
|
||||||
|
* provider/aws: Add ability to set canned ACL in `aws_s3_bucket_object` [GH-8091]
|
||||||
* provider/azurerm: Adds support for uploading blobs to azure storage from local source [GH-7994]
|
* provider/azurerm: Adds support for uploading blobs to azure storage from local source [GH-7994]
|
||||||
* provider/google: allows atomic Cloud DNS record changes [GH-6575]
|
* provider/google: allows atomic Cloud DNS record changes [GH-6575]
|
||||||
* provider/google: Move URLMap hosts to TypeSet from TypeList [GH-7472]
|
* provider/google: Move URLMap hosts to TypeSet from TypeList [GH-7472]
|
||||||
|
@ -30,7 +34,9 @@ BUG FIXES:
|
||||||
* provider/aws: Retry association of IAM Role & instance profile [GH-7938]
|
* provider/aws: Retry association of IAM Role & instance profile [GH-7938]
|
||||||
* provider/aws: Fix `aws_s3_bucket` resource `redirect_all_requests_to` action [GH-7883]
|
* provider/aws: Fix `aws_s3_bucket` resource `redirect_all_requests_to` action [GH-7883]
|
||||||
* provider/aws: Fix issue updating ElasticBeanstalk Environment Settings [GH-7777]
|
* provider/aws: Fix issue updating ElasticBeanstalk Environment Settings [GH-7777]
|
||||||
* providers/aws: `aws_rds_cluster` creation timeout bumped to 40 minutes [GH-8052]
|
* provider/aws: `aws_rds_cluster` creation timeout bumped to 40 minutes [GH-8052]
|
||||||
|
* provider/aws: Fix line ending errors/diffs with IAM Server Certs [GH-8074]
|
||||||
|
* provider/aws: Fixing IAM data source policy generation to prevent spurious diffs [GH-6956]
|
||||||
* provider/google: Use resource specific project when making queries/changes [GH-7029]
|
* provider/google: Use resource specific project when making queries/changes [GH-7029]
|
||||||
* provider/google: Fix read for the backend service resource [GH-7476]
|
* provider/google: Fix read for the backend service resource [GH-7476]
|
||||||
|
|
||||||
|
|
|
@ -150,12 +150,19 @@ func dataSourceAwsIamPolicyDocumentRead(d *schema.ResourceData, meta interface{}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func dataSourceAwsIamPolicyDocumentReplaceVarsInList(in []string) []string {
|
func dataSourceAwsIamPolicyDocumentReplaceVarsInList(in interface{}) interface{} {
|
||||||
out := make([]string, len(in))
|
switch v := in.(type) {
|
||||||
for i, item := range in {
|
case string:
|
||||||
out[i] = dataSourceAwsIamPolicyDocumentVarReplacer.Replace(item)
|
return dataSourceAwsIamPolicyDocumentVarReplacer.Replace(v)
|
||||||
|
case []string:
|
||||||
|
out := make([]string, len(v))
|
||||||
|
for i, item := range v {
|
||||||
|
out[i] = dataSourceAwsIamPolicyDocumentVarReplacer.Replace(item)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
default:
|
||||||
|
panic("dataSourceAwsIamPolicyDocumentReplaceVarsInList: input not string nor []string")
|
||||||
}
|
}
|
||||||
return out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func dataSourceAwsIamPolicyDocumentMakeConditions(in []interface{}) IAMPolicyStatementConditionSet {
|
func dataSourceAwsIamPolicyDocumentMakeConditions(in []interface{}) IAMPolicyStatementConditionSet {
|
||||||
|
|
|
@ -75,7 +75,6 @@ data "aws_iam_policy_document" "test" {
|
||||||
test = "StringLike"
|
test = "StringLike"
|
||||||
variable = "s3:prefix"
|
variable = "s3:prefix"
|
||||||
values = [
|
values = [
|
||||||
"",
|
|
||||||
"home/",
|
"home/",
|
||||||
"home/&{aws:username}/",
|
"home/&{aws:username}/",
|
||||||
]
|
]
|
||||||
|
@ -118,59 +117,45 @@ var testAccAWSIAMPolicyDocumentExpectedJSON = `{
|
||||||
"Sid": "1",
|
"Sid": "1",
|
||||||
"Effect": "Allow",
|
"Effect": "Allow",
|
||||||
"Action": [
|
"Action": [
|
||||||
"s3:GetBucketLocation",
|
"s3:ListAllMyBuckets",
|
||||||
"s3:ListAllMyBuckets"
|
"s3:GetBucketLocation"
|
||||||
],
|
],
|
||||||
"Resource": [
|
"Resource": "arn:aws:s3:::*"
|
||||||
"arn:aws:s3:::*"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"Sid": "",
|
||||||
"Effect": "Allow",
|
"Effect": "Allow",
|
||||||
"Action": [
|
"Action": "s3:ListBucket",
|
||||||
"s3:ListBucket"
|
"Resource": "arn:aws:s3:::foo",
|
||||||
],
|
|
||||||
"Resource": [
|
|
||||||
"arn:aws:s3:::foo"
|
|
||||||
],
|
|
||||||
"NotPrincipal": {
|
"NotPrincipal": {
|
||||||
"AWS": [
|
"AWS": "arn:blahblah:example"
|
||||||
"arn:blahblah:example"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"Condition": {
|
"Condition": {
|
||||||
"StringLike": {
|
"StringLike": {
|
||||||
"s3:prefix": [
|
"s3:prefix": [
|
||||||
"",
|
"home/${aws:username}/",
|
||||||
"home/",
|
"home/"
|
||||||
"home/${aws:username}/"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"Sid": "",
|
||||||
"Effect": "Allow",
|
"Effect": "Allow",
|
||||||
"Action": [
|
"Action": "s3:*",
|
||||||
"s3:*"
|
|
||||||
],
|
|
||||||
"Resource": [
|
"Resource": [
|
||||||
"arn:aws:s3:::foo/home/${aws:username}/*",
|
"arn:aws:s3:::foo/home/${aws:username}/*",
|
||||||
"arn:aws:s3:::foo/home/${aws:username}"
|
"arn:aws:s3:::foo/home/${aws:username}"
|
||||||
],
|
],
|
||||||
"Principal": {
|
"Principal": {
|
||||||
"AWS": [
|
"AWS": "arn:blahblah:example"
|
||||||
"arn:blahblah:example"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"Sid": "",
|
||||||
"Effect": "Deny",
|
"Effect": "Deny",
|
||||||
"NotAction": [
|
"NotAction": "s3:*",
|
||||||
"s3:*"
|
"NotResource": "arn:aws:s3:::*"
|
||||||
],
|
|
||||||
"NotResource": [
|
|
||||||
"arn:aws:s3:::*"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}`
|
}`
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
}
|
|
@ -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" ]
|
||||||
|
}
|
||||||
|
`
|
|
@ -2,6 +2,7 @@ package aws
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IAMPolicyDoc struct {
|
type IAMPolicyDoc struct {
|
||||||
|
@ -11,12 +12,12 @@ type IAMPolicyDoc struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type IAMPolicyStatement struct {
|
type IAMPolicyStatement struct {
|
||||||
Sid string `json:",omitempty"`
|
Sid string
|
||||||
Effect string `json:",omitempty"`
|
Effect string `json:",omitempty"`
|
||||||
Actions []string `json:"Action,omitempty"`
|
Actions interface{} `json:"Action,omitempty"`
|
||||||
NotActions []string `json:"NotAction,omitempty"`
|
NotActions interface{} `json:"NotAction,omitempty"`
|
||||||
Resources []string `json:"Resource,omitempty"`
|
Resources interface{} `json:"Resource,omitempty"`
|
||||||
NotResources []string `json:"NotResource,omitempty"`
|
NotResources interface{} `json:"NotResource,omitempty"`
|
||||||
Principals IAMPolicyStatementPrincipalSet `json:"Principal,omitempty"`
|
Principals IAMPolicyStatementPrincipalSet `json:"Principal,omitempty"`
|
||||||
NotPrincipals IAMPolicyStatementPrincipalSet `json:"NotPrincipal,omitempty"`
|
NotPrincipals IAMPolicyStatementPrincipalSet `json:"NotPrincipal,omitempty"`
|
||||||
Conditions IAMPolicyStatementConditionSet `json:"Condition,omitempty"`
|
Conditions IAMPolicyStatementConditionSet `json:"Condition,omitempty"`
|
||||||
|
@ -24,51 +25,71 @@ type IAMPolicyStatement struct {
|
||||||
|
|
||||||
type IAMPolicyStatementPrincipal struct {
|
type IAMPolicyStatementPrincipal struct {
|
||||||
Type string
|
Type string
|
||||||
Identifiers []string
|
Identifiers interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type IAMPolicyStatementCondition struct {
|
type IAMPolicyStatementCondition struct {
|
||||||
Test string
|
Test string
|
||||||
Variable string
|
Variable string
|
||||||
Values []string
|
Values interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type IAMPolicyStatementPrincipalSet []IAMPolicyStatementPrincipal
|
type IAMPolicyStatementPrincipalSet []IAMPolicyStatementPrincipal
|
||||||
type IAMPolicyStatementConditionSet []IAMPolicyStatementCondition
|
type IAMPolicyStatementConditionSet []IAMPolicyStatementCondition
|
||||||
|
|
||||||
func (ps IAMPolicyStatementPrincipalSet) MarshalJSON() ([]byte, error) {
|
func (ps IAMPolicyStatementPrincipalSet) MarshalJSON() ([]byte, error) {
|
||||||
raw := map[string][]string{}
|
raw := map[string]interface{}{}
|
||||||
|
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
if _, ok := raw[p.Type]; !ok {
|
switch i := p.Identifiers.(type) {
|
||||||
raw[p.Type] = make([]string, 0, len(p.Identifiers))
|
case []string:
|
||||||
|
if _, ok := raw[p.Type]; !ok {
|
||||||
|
raw[p.Type] = make([]string, 0, len(i))
|
||||||
|
}
|
||||||
|
sort.Sort(sort.Reverse(sort.StringSlice(i)))
|
||||||
|
raw[p.Type] = append(raw[p.Type].([]string), i...)
|
||||||
|
case string:
|
||||||
|
raw[p.Type] = i
|
||||||
|
default:
|
||||||
|
panic("Unsupported data type for IAMPolicyStatementPrincipalSet")
|
||||||
}
|
}
|
||||||
raw[p.Type] = append(raw[p.Type], p.Identifiers...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return json.Marshal(&raw)
|
return json.Marshal(&raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs IAMPolicyStatementConditionSet) MarshalJSON() ([]byte, error) {
|
func (cs IAMPolicyStatementConditionSet) MarshalJSON() ([]byte, error) {
|
||||||
raw := map[string]map[string][]string{}
|
raw := map[string]map[string]interface{}{}
|
||||||
|
|
||||||
for _, c := range cs {
|
for _, c := range cs {
|
||||||
if _, ok := raw[c.Test]; !ok {
|
if _, ok := raw[c.Test]; !ok {
|
||||||
raw[c.Test] = map[string][]string{}
|
raw[c.Test] = map[string]interface{}{}
|
||||||
}
|
}
|
||||||
if _, ok := raw[c.Test][c.Variable]; !ok {
|
switch i := c.Values.(type) {
|
||||||
raw[c.Test][c.Variable] = make([]string, 0, len(c.Values))
|
case []string:
|
||||||
|
if _, ok := raw[c.Test][c.Variable]; !ok {
|
||||||
|
raw[c.Test][c.Variable] = make([]string, 0, len(i))
|
||||||
|
}
|
||||||
|
sort.Sort(sort.Reverse(sort.StringSlice(i)))
|
||||||
|
raw[c.Test][c.Variable] = append(raw[c.Test][c.Variable].([]string), i...)
|
||||||
|
case string:
|
||||||
|
raw[c.Test][c.Variable] = i
|
||||||
|
default:
|
||||||
|
panic("Unsupported data type for IAMPolicyStatementConditionSet")
|
||||||
}
|
}
|
||||||
raw[c.Test][c.Variable] = append(raw[c.Test][c.Variable], c.Values...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return json.Marshal(&raw)
|
return json.Marshal(&raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func iamPolicyDecodeConfigStringList(lI []interface{}) []string {
|
func iamPolicyDecodeConfigStringList(lI []interface{}) interface{} {
|
||||||
|
if len(lI) == 1 {
|
||||||
|
return lI[0].(string)
|
||||||
|
}
|
||||||
ret := make([]string, len(lI))
|
ret := make([]string, len(lI))
|
||||||
for i, vI := range lI {
|
for i, vI := range lI {
|
||||||
ret[i] = vI.(string)
|
ret[i] = vI.(string)
|
||||||
}
|
}
|
||||||
|
sort.Sort(sort.Reverse(sort.StringSlice(ret)))
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccAWSRole_importBasic(t *testing.T) {
|
||||||
|
resourceName := "aws_iam_role.role"
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckAWSRoleDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccAWSRoleConfig,
|
||||||
|
},
|
||||||
|
|
||||||
|
resource.TestStep{
|
||||||
|
ResourceName: resourceName,
|
||||||
|
ImportState: true,
|
||||||
|
ImportStateVerify: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
|
@ -114,6 +114,7 @@ func Provider() terraform.ResourceProvider {
|
||||||
"aws_ami": dataSourceAwsAmi(),
|
"aws_ami": dataSourceAwsAmi(),
|
||||||
"aws_availability_zones": dataSourceAwsAvailabilityZones(),
|
"aws_availability_zones": dataSourceAwsAvailabilityZones(),
|
||||||
"aws_iam_policy_document": dataSourceAwsIamPolicyDocument(),
|
"aws_iam_policy_document": dataSourceAwsIamPolicyDocument(),
|
||||||
|
"aws_ip_ranges": dataSourceAwsIPRanges(),
|
||||||
"aws_s3_bucket_object": dataSourceAwsS3BucketObject(),
|
"aws_s3_bucket_object": dataSourceAwsS3BucketObject(),
|
||||||
"aws_ecs_container_definition": dataSourceAwsEcsContainerDefinition(),
|
"aws_ecs_container_definition": dataSourceAwsEcsContainerDefinition(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -120,8 +120,8 @@ func testAccCheckAWSInstanceProfileExists(n string, res *iam.GetInstanceProfileO
|
||||||
|
|
||||||
const testAccAwsIamInstanceProfileConfig = `
|
const testAccAwsIamInstanceProfileConfig = `
|
||||||
resource "aws_iam_role" "test" {
|
resource "aws_iam_role" "test" {
|
||||||
name = "test"
|
name = "test"
|
||||||
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}"
|
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_iam_instance_profile" "test" {
|
resource "aws_iam_instance_profile" "test" {
|
||||||
|
@ -132,8 +132,8 @@ resource "aws_iam_instance_profile" "test" {
|
||||||
|
|
||||||
const testAccAWSInstanceProfilePrefixNameConfig = `
|
const testAccAWSInstanceProfilePrefixNameConfig = `
|
||||||
resource "aws_iam_role" "test" {
|
resource "aws_iam_role" "test" {
|
||||||
name = "test"
|
name = "test"
|
||||||
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}"
|
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_iam_instance_profile" "test" {
|
resource "aws_iam_instance_profile" "test" {
|
||||||
|
|
|
@ -113,22 +113,8 @@ resource "aws_iam_user" "user" {
|
||||||
name = "test-user"
|
name = "test-user"
|
||||||
}
|
}
|
||||||
resource "aws_iam_role" "role" {
|
resource "aws_iam_role" "role" {
|
||||||
name = "test-role"
|
name = "test-role"
|
||||||
assume_role_policy = <<EOF
|
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
|
||||||
{
|
|
||||||
"Version": "2012-10-17",
|
|
||||||
"Statement": [
|
|
||||||
{
|
|
||||||
"Action": "sts:AssumeRole",
|
|
||||||
"Principal": {
|
|
||||||
"Service": "ec2.amazonaws.com"
|
|
||||||
},
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Sid": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_iam_group" "group" {
|
resource "aws_iam_group" "group" {
|
||||||
|
@ -174,61 +160,16 @@ resource "aws_iam_user" "user3" {
|
||||||
name = "test-user3"
|
name = "test-user3"
|
||||||
}
|
}
|
||||||
resource "aws_iam_role" "role" {
|
resource "aws_iam_role" "role" {
|
||||||
name = "test-role"
|
name = "test-role"
|
||||||
assume_role_policy = <<EOF
|
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
|
||||||
{
|
|
||||||
"Version": "2012-10-17",
|
|
||||||
"Statement": [
|
|
||||||
{
|
|
||||||
"Action": "sts:AssumeRole",
|
|
||||||
"Principal": {
|
|
||||||
"Service": "ec2.amazonaws.com"
|
|
||||||
},
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Sid": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "aws_iam_role" "role2" {
|
resource "aws_iam_role" "role2" {
|
||||||
name = "test-role2"
|
name = "test-role2"
|
||||||
assume_role_policy = <<EOF
|
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
|
||||||
{
|
|
||||||
"Version": "2012-10-17",
|
|
||||||
"Statement": [
|
|
||||||
{
|
|
||||||
"Action": "sts:AssumeRole",
|
|
||||||
"Principal": {
|
|
||||||
"Service": "ec2.amazonaws.com"
|
|
||||||
},
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Sid": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
}
|
}
|
||||||
resource "aws_iam_role" "role3" {
|
resource "aws_iam_role" "role3" {
|
||||||
name = "test-role3"
|
name = "test-role3"
|
||||||
assume_role_policy = <<EOF
|
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
|
||||||
{
|
|
||||||
"Version": "2012-10-17",
|
|
||||||
"Statement": [
|
|
||||||
{
|
|
||||||
"Action": "sts:AssumeRole",
|
|
||||||
"Principal": {
|
|
||||||
"Service": "ec2.amazonaws.com"
|
|
||||||
},
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Sid": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
}
|
}
|
||||||
resource "aws_iam_group" "group" {
|
resource "aws_iam_group" "group" {
|
||||||
name = "test-group"
|
name = "test-group"
|
||||||
|
|
|
@ -2,6 +2,7 @@ package aws
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -20,6 +21,10 @@ func resourceAwsIamRole() *schema.Resource {
|
||||||
Update: resourceAwsIamRoleUpdate,
|
Update: resourceAwsIamRoleUpdate,
|
||||||
Delete: resourceAwsIamRoleDelete,
|
Delete: resourceAwsIamRoleDelete,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: map[string]*schema.Schema{
|
||||||
"arn": &schema.Schema{
|
"arn": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
|
@ -174,6 +179,10 @@ func resourceAwsIamRoleReadResult(d *schema.ResourceData, role *iam.Role) error
|
||||||
if err := d.Set("unique_id", role.RoleId); err != nil {
|
if err := d.Set("unique_id", role.RoleId); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
policy, _ := url.QueryUnescape(*role.AssumeRolePolicyDocument)
|
||||||
|
if err := d.Set("assume_role_policy", aws.String(policy)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,22 +90,8 @@ func testAccCheckAWSRolePolicyAttachmentAttributes(policies []string, out *iam.L
|
||||||
|
|
||||||
const testAccAWSRolePolicyAttachConfig = `
|
const testAccAWSRolePolicyAttachConfig = `
|
||||||
resource "aws_iam_role" "role" {
|
resource "aws_iam_role" "role" {
|
||||||
name = "test-role"
|
name = "test-role"
|
||||||
assume_role_policy = <<EOF
|
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
|
||||||
{
|
|
||||||
"Version": "2012-10-17",
|
|
||||||
"Statement": [
|
|
||||||
{
|
|
||||||
"Action": "sts:AssumeRole",
|
|
||||||
"Principal": {
|
|
||||||
"Service": "ec2.amazonaws.com"
|
|
||||||
},
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Sid": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_iam_policy" "policy" {
|
resource "aws_iam_policy" "policy" {
|
||||||
|
@ -135,22 +121,8 @@ resource "aws_iam_role_policy_attachment" "test-attach" {
|
||||||
|
|
||||||
const testAccAWSRolePolicyAttachConfigUpdate = `
|
const testAccAWSRolePolicyAttachConfigUpdate = `
|
||||||
resource "aws_iam_role" "role" {
|
resource "aws_iam_role" "role" {
|
||||||
name = "test-role"
|
name = "test-role"
|
||||||
assume_role_policy = <<EOF
|
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
|
||||||
{
|
|
||||||
"Version": "2012-10-17",
|
|
||||||
"Statement": [
|
|
||||||
{
|
|
||||||
"Action": "sts:AssumeRole",
|
|
||||||
"Principal": {
|
|
||||||
"Service": "ec2.amazonaws.com"
|
|
||||||
},
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Sid": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_iam_policy" "policy" {
|
resource "aws_iam_policy" "policy" {
|
||||||
|
|
|
@ -113,15 +113,15 @@ func testAccCheckIAMRolePolicy(
|
||||||
func testAccIAMRolePolicyConfig(role, policy1 string) string {
|
func testAccIAMRolePolicyConfig(role, policy1 string) string {
|
||||||
return fmt.Sprintf(`
|
return fmt.Sprintf(`
|
||||||
resource "aws_iam_role" "role" {
|
resource "aws_iam_role" "role" {
|
||||||
name = "tf_test_role_%s"
|
name = "tf_test_role_%s"
|
||||||
path = "/"
|
path = "/"
|
||||||
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Effect\":\"Allow\",\"Sid\":\"\"}]}"
|
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_iam_role_policy" "foo" {
|
resource "aws_iam_role_policy" "foo" {
|
||||||
name = "tf_test_policy_%s"
|
name = "tf_test_policy_%s"
|
||||||
role = "${aws_iam_role.role.name}"
|
role = "${aws_iam_role.role.name}"
|
||||||
policy = "{\"Version\":\"2012-10-17\",\"Statement\":{\"Effect\":\"Allow\",\"Action\":\"*\",\"Resource\":\"*\"}}"
|
policy = "{\"Version\":\"2012-10-17\",\"Statement\":{\"Effect\":\"Allow\",\"Action\":\"*\",\"Resource\":\"*\"}}"
|
||||||
}
|
}
|
||||||
`, role, policy1)
|
`, role, policy1)
|
||||||
}
|
}
|
||||||
|
@ -129,21 +129,21 @@ resource "aws_iam_role_policy" "foo" {
|
||||||
func testAccIAMRolePolicyConfigUpdate(role, policy1, policy2 string) string {
|
func testAccIAMRolePolicyConfigUpdate(role, policy1, policy2 string) string {
|
||||||
return fmt.Sprintf(`
|
return fmt.Sprintf(`
|
||||||
resource "aws_iam_role" "role" {
|
resource "aws_iam_role" "role" {
|
||||||
name = "tf_test_role_%s"
|
name = "tf_test_role_%s"
|
||||||
path = "/"
|
path = "/"
|
||||||
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Effect\":\"Allow\",\"Sid\":\"\"}]}"
|
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_iam_role_policy" "foo" {
|
resource "aws_iam_role_policy" "foo" {
|
||||||
name = "tf_test_policy_%s"
|
name = "tf_test_policy_%s"
|
||||||
role = "${aws_iam_role.role.name}"
|
role = "${aws_iam_role.role.name}"
|
||||||
policy = "{\"Version\":\"2012-10-17\",\"Statement\":{\"Effect\":\"Allow\",\"Action\":\"*\",\"Resource\":\"*\"}}"
|
policy = "{\"Version\":\"2012-10-17\",\"Statement\":{\"Effect\":\"Allow\",\"Action\":\"*\",\"Resource\":\"*\"}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_iam_role_policy" "bar" {
|
resource "aws_iam_role_policy" "bar" {
|
||||||
name = "tf_test_policy_2_%s"
|
name = "tf_test_policy_2_%s"
|
||||||
role = "${aws_iam_role.role.name}"
|
role = "${aws_iam_role.role.name}"
|
||||||
policy = "{\"Version\":\"2012-10-17\",\"Statement\":{\"Effect\":\"Allow\",\"Action\":\"*\",\"Resource\":\"*\"}}"
|
policy = "{\"Version\":\"2012-10-17\",\"Statement\":{\"Effect\":\"Allow\",\"Action\":\"*\",\"Resource\":\"*\"}}"
|
||||||
}
|
}
|
||||||
`, role, policy1, policy2)
|
`, role, policy1, policy2)
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,39 +165,24 @@ func testAccCheckAWSRoleAttributes(role *iam.GetRoleOutput) resource.TestCheckFu
|
||||||
|
|
||||||
const testAccAWSRoleConfig = `
|
const testAccAWSRoleConfig = `
|
||||||
resource "aws_iam_role" "role" {
|
resource "aws_iam_role" "role" {
|
||||||
name = "test-role"
|
name = "test-role"
|
||||||
path = "/"
|
path = "/"
|
||||||
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}"
|
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const testAccAWSRolePrefixNameConfig = `
|
const testAccAWSRolePrefixNameConfig = `
|
||||||
resource "aws_iam_role" "role" {
|
resource "aws_iam_role" "role" {
|
||||||
name_prefix = "test-role-"
|
name_prefix = "test-role-"
|
||||||
path = "/"
|
path = "/"
|
||||||
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}"
|
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const testAccAWSRolePre = `
|
const testAccAWSRolePre = `
|
||||||
resource "aws_iam_role" "role_update_test" {
|
resource "aws_iam_role" "role_update_test" {
|
||||||
name = "tf_old_name"
|
name = "tf_old_name"
|
||||||
path = "/test/"
|
path = "/test/"
|
||||||
assume_role_policy = <<EOF
|
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
|
||||||
{
|
|
||||||
"Version": "2012-10-17",
|
|
||||||
"Statement": [
|
|
||||||
{
|
|
||||||
"Action": "sts:AssumeRole",
|
|
||||||
"Principal": {
|
|
||||||
"Service": "ec2.amazonaws.com"
|
|
||||||
},
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Sid": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_iam_role_policy" "role_update_test" {
|
resource "aws_iam_role_policy" "role_update_test" {
|
||||||
|
@ -232,21 +217,7 @@ const testAccAWSRolePost = `
|
||||||
resource "aws_iam_role" "role_update_test" {
|
resource "aws_iam_role" "role_update_test" {
|
||||||
name = "tf_new_name"
|
name = "tf_new_name"
|
||||||
path = "/test/"
|
path = "/test/"
|
||||||
assume_role_policy = <<EOF
|
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
|
||||||
{
|
|
||||||
"Version": "2012-10-17",
|
|
||||||
"Statement": [
|
|
||||||
{
|
|
||||||
"Action": "sts:AssumeRole",
|
|
||||||
"Principal": {
|
|
||||||
"Service": "ec2.amazonaws.com"
|
|
||||||
},
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Sid": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_iam_role_policy" "role_update_test" {
|
resource "aws_iam_role_policy" "role_update_test" {
|
||||||
|
|
|
@ -201,14 +201,30 @@ func normalizeCert(cert interface{}) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var rawCert string
|
||||||
switch cert.(type) {
|
switch cert.(type) {
|
||||||
case string:
|
case string:
|
||||||
hash := sha1.Sum([]byte(strings.TrimSpace(cert.(string))))
|
rawCert = cert.(string)
|
||||||
return hex.EncodeToString(hash[:])
|
|
||||||
case *string:
|
case *string:
|
||||||
hash := sha1.Sum([]byte(strings.TrimSpace(*cert.(*string))))
|
rawCert = *cert.(*string)
|
||||||
return hex.EncodeToString(hash[:])
|
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanVal := sha1.Sum(stripCR([]byte(strings.TrimSpace(rawCert))))
|
||||||
|
return hex.EncodeToString(cleanVal[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// strip CRs from raw literals. Lifted from go/scanner/scanner.go
|
||||||
|
// See https://github.com/golang/go/blob/release-branch.go1.6/src/go/scanner/scanner.go#L479
|
||||||
|
func stripCR(b []byte) []byte {
|
||||||
|
c := make([]byte, len(b))
|
||||||
|
i := 0
|
||||||
|
for _, ch := range b {
|
||||||
|
if ch != '\r' {
|
||||||
|
c[i] = ch
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c[:i]
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/service/iam"
|
"github.com/aws/aws-sdk-go/service/iam"
|
||||||
|
"github.com/hashicorp/terraform/helper/acctest"
|
||||||
"github.com/hashicorp/terraform/helper/resource"
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
)
|
)
|
||||||
|
@ -86,6 +87,35 @@ func TestAccAWSIAMServerCertificate_disappears(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAccAWSIAMServerCertificate_file(t *testing.T) {
|
||||||
|
var cert iam.ServerCertificate
|
||||||
|
|
||||||
|
rInt := acctest.RandInt()
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckIAMServerCertificateDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccIAMServerCertConfig_file(rInt, "iam-ssl-unix-line-endings"),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckCertExists("aws_iam_server_certificate.test_cert", &cert),
|
||||||
|
testAccCheckAWSServerCertAttributes(&cert),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccIAMServerCertConfig_file(rInt, "iam-ssl-windows-line-endings"),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckCertExists("aws_iam_server_certificate.test_cert", &cert),
|
||||||
|
testAccCheckAWSServerCertAttributes(&cert),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func testAccCheckCertExists(n string, cert *iam.ServerCertificate) resource.TestCheckFunc {
|
func testAccCheckCertExists(n string, cert *iam.ServerCertificate) resource.TestCheckFunc {
|
||||||
return func(s *terraform.State) error {
|
return func(s *terraform.State) error {
|
||||||
rs, ok := s.RootModule().Resources[n]
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
@ -285,3 +315,43 @@ dg+Sd4Wjm89UQoUUoiIcstY7FPbqfBtYKfh4RYHAHV2BwDFqzZCM
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
// iam-ssl-unix-line-endings
|
||||||
|
func testAccIAMServerCertConfig_file(rInt int, fName string) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
resource "aws_iam_server_certificate" "test_cert" {
|
||||||
|
name = "terraform-test-cert-%d"
|
||||||
|
certificate_body = "${file("test-fixtures/%s.pem")}"
|
||||||
|
|
||||||
|
private_key = <<EOF
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEowIBAAKCAQEAv4sWWwIkbm3FmnjK676VCe5SuAFdEb6KtCpxNeVX3UGnmGmZ
|
||||||
|
EjKGcYK1bHEMFQvGuHhY3dVX/SMPMpP3vqguA7LeGPnoJ2p/4mVnWqAw3lscHeab
|
||||||
|
dpVaeuewtsGx/BlIRuTcqG39wTWcra2g1Vb6vOdLeb56hXdmf8NQ3AaVmvjaEY2z
|
||||||
|
oROfaNRFjvwROpGZbjvG+N/zp4iju9QsclpjrHJqs+qQvwNlrM6a9jTqFQa8bAYG
|
||||||
|
fLuC6B9eoMb4jydw8GwYkZICYeZVXyjREIH1SNj5O9IxBGkQOhWW/Ksa6CWwPy2j
|
||||||
|
/j7tRyy4MaVFg3qOYg4LfuY6L+PBF9YvVhRrgwIDAQABAoIBAFqJ4h1Om+3e0WK8
|
||||||
|
6h4YzdYN4ue7LUTv7hxPW4gASlH5cMDoWURywX3yLNN/dBiWom4b5NWmvJqY8dwU
|
||||||
|
eSyTznxNFhJ0PjozaxOWnw4FXlQceOPhV2bsHgKudadNU1Y4lSN9lpe+tg2Xy+GE
|
||||||
|
ituM66RTKCf502w3DioiJpx6OEkxuhrnsQAWNcGB0MnTukm2f+629V+04R5MT5V1
|
||||||
|
nY+5Phx2BpHgYzWBKh6Px1puu7xFv5SMQda1ndlPIKb4cNp0yYn+1lHNjbOE7QL/
|
||||||
|
oEpWgrauS5Zk/APK33v/p3wVYHrKocIFHlPiCW0uIJJLsOZDY8pQXpTlc+/xGLLy
|
||||||
|
WBu4boECgYEA6xO+1UNh6ndJ3xGuNippH+ucTi/uq1+0tG1bd63v+75tn5l4LyY2
|
||||||
|
CWHRaWVlVn+WnDslkQTJzFD68X+9M7Cc4oP6WnhTyPamG7HlGv5JxfFHTC9GOKmz
|
||||||
|
sSc624BDmqYJ7Xzyhe5kc3iHzqG/L72ZF1aijZdrodQMSY1634UX6aECgYEA0Jdr
|
||||||
|
cBPSN+mgmEY6ogN5h7sO5uNV3TQQtW2IslfWZn6JhSRF4Rf7IReng48CMy9ZhFBy
|
||||||
|
Q7H2I1pDGjEC9gQHhgVfm+FyMSVqXfCHEW/97pvvu9ougHA0MhPep1twzTGrqg+K
|
||||||
|
f3PLW8hVkGyCrTfWgbDlPsHgsocA/wTaQOheaqMCgYBat5z+WemQfQZh8kXDm2xE
|
||||||
|
KD2Cota9BcsLkeQpdFNXWC6f167cqydRSZFx1fJchhJOKjkeFLX3hgzBY6VVLEPu
|
||||||
|
2jWj8imLNTv3Fhiu6RD5NVppWRkFRuAUbmo1SPNN2+Oa5YwGCXB0a0Alip/oQYex
|
||||||
|
zPogIB4mLlmrjNCtL4SB4QKBgCEHKMrZSJrz0irqS9RlanPUaZqjenAJE3A2xMNA
|
||||||
|
Z0FZXdsIEEyA6JGn1i1dkoKaR7lMp5sSbZ/RZfiatBZSMwLEjQv4mYUwoHP5Ztma
|
||||||
|
+wEyDbaX6G8L1Sfsv3+OWgETkVPfHBXsNtH0mZ/BnrtgsQVeBh52wmZiPAUlNo26
|
||||||
|
fWCzAoGBAJOjqovLelLWzyQGqPFx/MwuI56UFXd1CmFlCIvF2WxCFmk3tlExoCN1
|
||||||
|
HqSpt92vsgYgV7+lAb4U7Uy/v012gwiU1LK+vyAE9geo3pTjG73BNzG4H547xtbY
|
||||||
|
dg+Sd4Wjm89UQoUUoiIcstY7FPbqfBtYKfh4RYHAHV2BwDFqzZCM
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
`, rInt, fName)
|
||||||
|
}
|
||||||
|
|
|
@ -286,8 +286,6 @@ func resourceAwsS3Bucket() *schema.Resource {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
"tags": tagsSchema(),
|
|
||||||
|
|
||||||
"force_destroy": &schema.Schema{
|
"force_destroy": &schema.Schema{
|
||||||
Type: schema.TypeBool,
|
Type: schema.TypeBool,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
|
@ -300,6 +298,15 @@ func resourceAwsS3Bucket() *schema.Resource {
|
||||||
Computed: true,
|
Computed: true,
|
||||||
ValidateFunc: validateS3BucketAccelerationStatus,
|
ValidateFunc: validateS3BucketAccelerationStatus,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"request_payer": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
ValidateFunc: validateS3BucketRequestPayerType,
|
||||||
|
},
|
||||||
|
|
||||||
|
"tags": tagsSchema(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -408,6 +415,12 @@ func resourceAwsS3BucketUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if d.HasChange("request_payer") {
|
||||||
|
if err := resourceAwsS3BucketRequestPayerUpdate(s3conn, d); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return resourceAwsS3BucketRead(d, meta)
|
return resourceAwsS3BucketRead(d, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,6 +581,20 @@ func resourceAwsS3BucketRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
d.Set("acceleration_status", accelerate.Status)
|
d.Set("acceleration_status", accelerate.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read the request payer configuration.
|
||||||
|
payer, err := s3conn.GetBucketRequestPayment(&s3.GetBucketRequestPaymentInput{
|
||||||
|
Bucket: aws.String(d.Id()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Printf("[DEBUG] S3 Bucket: %s, read request payer: %v", d.Id(), payer)
|
||||||
|
if payer.Payer != nil {
|
||||||
|
if err := d.Set("request_payer", *payer.Payer); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Read the logging configuration
|
// Read the logging configuration
|
||||||
logging, err := s3conn.GetBucketLogging(&s3.GetBucketLoggingInput{
|
logging, err := s3conn.GetBucketLogging(&s3.GetBucketLoggingInput{
|
||||||
Bucket: aws.String(d.Id()),
|
Bucket: aws.String(d.Id()),
|
||||||
|
@ -575,6 +602,7 @@ func resourceAwsS3BucketRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("[DEBUG] S3 Bucket: %s, logging: %v", d.Id(), logging)
|
log.Printf("[DEBUG] S3 Bucket: %s, logging: %v", d.Id(), logging)
|
||||||
if v := logging.LoggingEnabled; v != nil {
|
if v := logging.LoggingEnabled; v != nil {
|
||||||
lcl := make([]map[string]interface{}, 0, 1)
|
lcl := make([]map[string]interface{}, 0, 1)
|
||||||
|
@ -1163,6 +1191,26 @@ func resourceAwsS3BucketAccelerationUpdate(s3conn *s3.S3, d *schema.ResourceData
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resourceAwsS3BucketRequestPayerUpdate(s3conn *s3.S3, d *schema.ResourceData) error {
|
||||||
|
bucket := d.Get("bucket").(string)
|
||||||
|
payer := d.Get("request_payer").(string)
|
||||||
|
|
||||||
|
i := &s3.PutBucketRequestPaymentInput{
|
||||||
|
Bucket: aws.String(bucket),
|
||||||
|
RequestPaymentConfiguration: &s3.RequestPaymentConfiguration{
|
||||||
|
Payer: aws.String(payer),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
log.Printf("[DEBUG] S3 put bucket request payer: %#v", i)
|
||||||
|
|
||||||
|
_, err := s3conn.PutBucketRequestPayment(i)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error putting S3 request payer: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func resourceAwsS3BucketLifecycleUpdate(s3conn *s3.S3, d *schema.ResourceData) error {
|
func resourceAwsS3BucketLifecycleUpdate(s3conn *s3.S3, d *schema.ResourceData) error {
|
||||||
bucket := d.Get("bucket").(string)
|
bucket := d.Get("bucket").(string)
|
||||||
|
|
||||||
|
@ -1370,6 +1418,16 @@ func validateS3BucketAccelerationStatus(v interface{}, k string) (ws []string, e
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateS3BucketRequestPayerType(v interface{}, k string) (ws []string, errors []error) {
|
||||||
|
value := v.(string)
|
||||||
|
if value != s3.PayerRequester && value != s3.PayerBucketOwner {
|
||||||
|
errors = append(errors, fmt.Errorf(
|
||||||
|
"%q contains an invalid Request Payer type %q. Valid types are either %q or %q",
|
||||||
|
k, value, s3.PayerRequester, s3.PayerBucketOwner))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func expirationHash(v interface{}) int {
|
func expirationHash(v interface{}) int {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
m := v.(map[string]interface{})
|
m := v.(map[string]interface{})
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
@ -30,6 +31,13 @@ func resourceAwsS3BucketObject() *schema.Resource {
|
||||||
ForceNew: true,
|
ForceNew: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"acl": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Default: "private",
|
||||||
|
Optional: true,
|
||||||
|
ValidateFunc: validateS3BucketObjectAclType,
|
||||||
|
},
|
||||||
|
|
||||||
"cache_control": &schema.Schema{
|
"cache_control": &schema.Schema{
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
|
@ -101,6 +109,7 @@ func resourceAwsS3BucketObjectPut(d *schema.ResourceData, meta interface{}) erro
|
||||||
|
|
||||||
bucket := d.Get("bucket").(string)
|
bucket := d.Get("bucket").(string)
|
||||||
key := d.Get("key").(string)
|
key := d.Get("key").(string)
|
||||||
|
acl := d.Get("acl").(string)
|
||||||
var body io.ReadSeeker
|
var body io.ReadSeeker
|
||||||
|
|
||||||
if v, ok := d.GetOk("source"); ok {
|
if v, ok := d.GetOk("source"); ok {
|
||||||
|
@ -131,6 +140,7 @@ func resourceAwsS3BucketObjectPut(d *schema.ResourceData, meta interface{}) erro
|
||||||
putInput := &s3.PutObjectInput{
|
putInput := &s3.PutObjectInput{
|
||||||
Bucket: aws.String(bucket),
|
Bucket: aws.String(bucket),
|
||||||
Key: aws.String(key),
|
Key: aws.String(key),
|
||||||
|
ACL: aws.String(acl),
|
||||||
Body: body,
|
Body: body,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,3 +261,39 @@ func resourceAwsS3BucketObjectDelete(d *schema.ResourceData, meta interface{}) e
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateS3BucketObjectAclType(v interface{}, k string) (ws []string, errors []error) {
|
||||||
|
value := v.(string)
|
||||||
|
|
||||||
|
cannedAcls := map[string]bool{
|
||||||
|
s3.ObjectCannedACLPrivate: true,
|
||||||
|
s3.ObjectCannedACLPublicRead: true,
|
||||||
|
s3.ObjectCannedACLPublicReadWrite: true,
|
||||||
|
s3.ObjectCannedACLAuthenticatedRead: true,
|
||||||
|
s3.ObjectCannedACLAwsExecRead: true,
|
||||||
|
s3.ObjectCannedACLBucketOwnerRead: true,
|
||||||
|
s3.ObjectCannedACLBucketOwnerFullControl: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
sentenceJoin := func(m map[string]bool) string {
|
||||||
|
keys := make([]string, 0, len(m))
|
||||||
|
for k := range m {
|
||||||
|
keys = append(keys, fmt.Sprintf("%q", k))
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
length := len(keys)
|
||||||
|
words := make([]string, length)
|
||||||
|
copy(words, keys)
|
||||||
|
|
||||||
|
words[length-1] = fmt.Sprintf("or %s", words[length-1])
|
||||||
|
return strings.Join(words, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := cannedAcls[value]; !ok {
|
||||||
|
errors = append(errors, fmt.Errorf(
|
||||||
|
"%q contains an invalid canned ACL type %q. Valid types are either %s",
|
||||||
|
k, value, sentenceJoin(cannedAcls)))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/acctest"
|
"github.com/hashicorp/terraform/helper/acctest"
|
||||||
|
@ -265,6 +267,104 @@ func TestAccAWSS3BucketObject_kms(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAccAWSS3BucketObject_acl(t *testing.T) {
|
||||||
|
rInt := acctest.RandInt()
|
||||||
|
var obj s3.GetObjectOutput
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckAWSS3BucketObjectDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccAWSS3BucketObjectConfig_acl(rInt, "private"),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckAWSS3BucketObjectExists(
|
||||||
|
"aws_s3_bucket_object.object", &obj),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"aws_s3_bucket_object.object",
|
||||||
|
"acl",
|
||||||
|
"private"),
|
||||||
|
testAccCheckAWSS3BucketObjectAcl(
|
||||||
|
"aws_s3_bucket_object.object",
|
||||||
|
[]string{"FULL_CONTROL"}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccAWSS3BucketObjectConfig_acl(rInt, "public-read"),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckAWSS3BucketObjectExists(
|
||||||
|
"aws_s3_bucket_object.object",
|
||||||
|
&obj),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"aws_s3_bucket_object.object",
|
||||||
|
"acl",
|
||||||
|
"public-read"),
|
||||||
|
testAccCheckAWSS3BucketObjectAcl(
|
||||||
|
"aws_s3_bucket_object.object",
|
||||||
|
[]string{"FULL_CONTROL", "READ"}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResourceAWSS3BucketObjectAcl_validation(t *testing.T) {
|
||||||
|
_, errors := validateS3BucketObjectAclType("incorrect", "acl")
|
||||||
|
if len(errors) == 0 {
|
||||||
|
t.Fatalf("Expected to trigger a validation error")
|
||||||
|
}
|
||||||
|
|
||||||
|
var testCases = []struct {
|
||||||
|
Value string
|
||||||
|
ErrCount int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Value: "public-read",
|
||||||
|
ErrCount: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Value: "public-read-write",
|
||||||
|
ErrCount: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
_, errors := validateS3BucketObjectAclType(tc.Value, "acl")
|
||||||
|
if len(errors) != tc.ErrCount {
|
||||||
|
t.Fatalf("Expected not to trigger a validation error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckAWSS3BucketObjectAcl(n string, expectedPerms []string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, _ := s.RootModule().Resources[n]
|
||||||
|
s3conn := testAccProvider.Meta().(*AWSClient).s3conn
|
||||||
|
|
||||||
|
out, err := s3conn.GetObjectAcl(&s3.GetObjectAclInput{
|
||||||
|
Bucket: aws.String(rs.Primary.Attributes["bucket"]),
|
||||||
|
Key: aws.String(rs.Primary.Attributes["key"]),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("GetObjectAcl error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var perms []string
|
||||||
|
for _, v := range out.Grants {
|
||||||
|
perms = append(perms, *v.Permission)
|
||||||
|
}
|
||||||
|
sort.Strings(perms)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(perms, expectedPerms) {
|
||||||
|
return fmt.Errorf("Expected ACL permissions to be %v, got %v", expectedPerms, perms)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testAccAWSS3BucketObjectConfigSource(randInt int, source string) string {
|
func testAccAWSS3BucketObjectConfigSource(randInt int, source string) string {
|
||||||
return fmt.Sprintf(`
|
return fmt.Sprintf(`
|
||||||
resource "aws_s3_bucket" "object_bucket" {
|
resource "aws_s3_bucket" "object_bucket" {
|
||||||
|
@ -358,3 +458,17 @@ resource "aws_s3_bucket_object" "object" {
|
||||||
}
|
}
|
||||||
`, randInt)
|
`, randInt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testAccAWSS3BucketObjectConfig_acl(randInt int, acl string) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
resource "aws_s3_bucket" "object_bucket" {
|
||||||
|
bucket = "tf-object-test-bucket-%d"
|
||||||
|
}
|
||||||
|
resource "aws_s3_bucket_object" "object" {
|
||||||
|
bucket = "${aws_s3_bucket.object_bucket.bucket}"
|
||||||
|
key = "test-key"
|
||||||
|
content = "some_bucket_content"
|
||||||
|
acl = "%s"
|
||||||
|
}
|
||||||
|
`, randInt, acl)
|
||||||
|
}
|
||||||
|
|
|
@ -77,6 +77,72 @@ func TestAccAWSS3Bucket_acceleration(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAccAWSS3Bucket_RequestPayer(t *testing.T) {
|
||||||
|
rInt := acctest.RandInt()
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckAWSS3BucketDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccAWSS3BucketConfigRequestPayerBucketOwner(rInt),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"aws_s3_bucket.bucket",
|
||||||
|
"request_payer",
|
||||||
|
"BucketOwner"),
|
||||||
|
testAccCheckAWSS3RequestPayer(
|
||||||
|
"aws_s3_bucket.bucket",
|
||||||
|
"BucketOwner"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccAWSS3BucketConfigRequestPayerRequester(rInt),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"aws_s3_bucket.bucket",
|
||||||
|
"request_payer",
|
||||||
|
"Requester"),
|
||||||
|
testAccCheckAWSS3RequestPayer(
|
||||||
|
"aws_s3_bucket.bucket",
|
||||||
|
"Requester"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResourceAWSS3BucketRequestPayer_validation(t *testing.T) {
|
||||||
|
_, errors := validateS3BucketRequestPayerType("incorrect", "request_payer")
|
||||||
|
if len(errors) == 0 {
|
||||||
|
t.Fatalf("Expected to trigger a validation error")
|
||||||
|
}
|
||||||
|
|
||||||
|
var testCases = []struct {
|
||||||
|
Value string
|
||||||
|
ErrCount int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Value: "Requester",
|
||||||
|
ErrCount: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Value: "BucketOwner",
|
||||||
|
ErrCount: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
_, errors := validateS3BucketRequestPayerType(tc.Value, "request_payer")
|
||||||
|
if len(errors) != tc.ErrCount {
|
||||||
|
t.Fatalf("Expected not to trigger a validation error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAccAWSS3Bucket_Policy(t *testing.T) {
|
func TestAccAWSS3Bucket_Policy(t *testing.T) {
|
||||||
rInt := acctest.RandInt()
|
rInt := acctest.RandInt()
|
||||||
|
|
||||||
|
@ -689,6 +755,28 @@ func testAccCheckAWSS3BucketCors(n string, corsRules []*s3.CORSRule) resource.Te
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testAccCheckAWSS3RequestPayer(n, expectedPayer string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, _ := s.RootModule().Resources[n]
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).s3conn
|
||||||
|
|
||||||
|
out, err := conn.GetBucketRequestPayment(&s3.GetBucketRequestPaymentInput{
|
||||||
|
Bucket: aws.String(rs.Primary.ID),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("GetBucketRequestPayment error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *out.Payer != expectedPayer {
|
||||||
|
return fmt.Errorf("bad error request payer type, expected: %v, got %v",
|
||||||
|
expectedPayer, out.Payer)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testAccCheckAWSS3BucketLogging(n, b, p string) resource.TestCheckFunc {
|
func testAccCheckAWSS3BucketLogging(n, b, p string) resource.TestCheckFunc {
|
||||||
return func(s *terraform.State) error {
|
return func(s *terraform.State) error {
|
||||||
rs, _ := s.RootModule().Resources[n]
|
rs, _ := s.RootModule().Resources[n]
|
||||||
|
@ -844,6 +932,26 @@ resource "aws_s3_bucket" "bucket" {
|
||||||
`, randInt)
|
`, randInt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testAccAWSS3BucketConfigRequestPayerBucketOwner(randInt int) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
resource "aws_s3_bucket" "bucket" {
|
||||||
|
bucket = "tf-test-bucket-%d"
|
||||||
|
acl = "public-read"
|
||||||
|
request_payer = "BucketOwner"
|
||||||
|
}
|
||||||
|
`, randInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccAWSS3BucketConfigRequestPayerRequester(randInt int) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
resource "aws_s3_bucket" "bucket" {
|
||||||
|
bucket = "tf-test-bucket-%d"
|
||||||
|
acl = "public-read"
|
||||||
|
request_payer = "Requester"
|
||||||
|
}
|
||||||
|
`, randInt)
|
||||||
|
}
|
||||||
|
|
||||||
func testAccAWSS3BucketConfigWithPolicy(randInt int) string {
|
func testAccAWSS3BucketConfigWithPolicy(randInt int) string {
|
||||||
return fmt.Sprintf(`
|
return fmt.Sprintf(`
|
||||||
resource "aws_s3_bucket" "bucket" {
|
resource "aws_s3_bucket" "bucket" {
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDBjCCAe4CCQCGWwBmOiHQdTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
|
||||||
|
VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
|
||||||
|
cyBQdHkgTHRkMB4XDTE2MDYyMTE2MzM0MVoXDTE3MDYyMTE2MzM0MVowRTELMAkG
|
||||||
|
A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0
|
||||||
|
IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||||
|
AL+LFlsCJG5txZp4yuu+lQnuUrgBXRG+irQqcTXlV91Bp5hpmRIyhnGCtWxxDBUL
|
||||||
|
xrh4WN3VV/0jDzKT976oLgOy3hj56Cdqf+JlZ1qgMN5bHB3mm3aVWnrnsLbBsfwZ
|
||||||
|
SEbk3Kht/cE1nK2toNVW+rznS3m+eoV3Zn/DUNwGlZr42hGNs6ETn2jURY78ETqR
|
||||||
|
mW47xvjf86eIo7vULHJaY6xyarPqkL8DZazOmvY06hUGvGwGBny7gugfXqDG+I8n
|
||||||
|
cPBsGJGSAmHmVV8o0RCB9UjY+TvSMQRpEDoVlvyrGuglsD8to/4+7UcsuDGlRYN6
|
||||||
|
jmIOC37mOi/jwRfWL1YUa4MCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAPDxTH0oQ
|
||||||
|
JjKXoJgkmQxurB81RfnK/NrswJVzWbOv6ejcbhwh+/ZgJTMc15BrYcxU6vUW1V/i
|
||||||
|
Z7APU0qJ0icECACML+a2fRI7YdLCTiPIOmY66HY8MZHAn3dGjU5TeiUflC0n0zkP
|
||||||
|
mxKJe43kcYLNDItbfvUDo/GoxTXrC3EFVZyU0RhFzoVJdODlTHXMVFCzcbQEBrBJ
|
||||||
|
xKdShCEc8nFMneZcGFeEU488ntZoWzzms8/QpYrKa5S0Sd7umEU2Kwu4HTkvUFg/
|
||||||
|
CqDUFjhydXxYRsxXBBrEiLOE5BdtJR1sH/QHxIJe23C9iHI2nS1NbLziNEApLwC4
|
||||||
|
GnSud83VUo9G9w==
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -0,0 +1,19 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDBjCCAe4CCQCGWwBmOiHQdTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
|
||||||
|
VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
|
||||||
|
cyBQdHkgTHRkMB4XDTE2MDYyMTE2MzM0MVoXDTE3MDYyMTE2MzM0MVowRTELMAkG
|
||||||
|
A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0
|
||||||
|
IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||||
|
AL+LFlsCJG5txZp4yuu+lQnuUrgBXRG+irQqcTXlV91Bp5hpmRIyhnGCtWxxDBUL
|
||||||
|
xrh4WN3VV/0jDzKT976oLgOy3hj56Cdqf+JlZ1qgMN5bHB3mm3aVWnrnsLbBsfwZ
|
||||||
|
SEbk3Kht/cE1nK2toNVW+rznS3m+eoV3Zn/DUNwGlZr42hGNs6ETn2jURY78ETqR
|
||||||
|
mW47xvjf86eIo7vULHJaY6xyarPqkL8DZazOmvY06hUGvGwGBny7gugfXqDG+I8n
|
||||||
|
cPBsGJGSAmHmVV8o0RCB9UjY+TvSMQRpEDoVlvyrGuglsD8to/4+7UcsuDGlRYN6
|
||||||
|
jmIOC37mOi/jwRfWL1YUa4MCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAPDxTH0oQ
|
||||||
|
JjKXoJgkmQxurB81RfnK/NrswJVzWbOv6ejcbhwh+/ZgJTMc15BrYcxU6vUW1V/i
|
||||||
|
Z7APU0qJ0icECACML+a2fRI7YdLCTiPIOmY66HY8MZHAn3dGjU5TeiUflC0n0zkP
|
||||||
|
mxKJe43kcYLNDItbfvUDo/GoxTXrC3EFVZyU0RhFzoVJdODlTHXMVFCzcbQEBrBJ
|
||||||
|
xKdShCEc8nFMneZcGFeEU488ntZoWzzms8/QpYrKa5S0Sd7umEU2Kwu4HTkvUFg/
|
||||||
|
CqDUFjhydXxYRsxXBBrEiLOE5BdtJR1sH/QHxIJe23C9iHI2nS1NbLziNEApLwC4
|
||||||
|
GnSud83VUo9G9w==
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -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
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package fastly
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccFastlyIPRanges(t *testing.T) {
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccFastlyIPRangesConfig,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccFastlyIPRanges("data.fastly_ip_ranges.some"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccFastlyIPRanges(n string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
|
||||||
|
r := s.RootModule().Resources[n]
|
||||||
|
a := r.Primary.Attributes
|
||||||
|
|
||||||
|
var (
|
||||||
|
cidrBlockSize int
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if cidrBlockSize, err = strconv.Atoi(a["cidr_blocks.#"]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if cidrBlockSize < 10 {
|
||||||
|
return fmt.Errorf("cidr_blocks seem suspiciously low: %d", cidrBlockSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccFastlyIPRangesConfig = `
|
||||||
|
data "fastly_ip_ranges" "some" {
|
||||||
|
}
|
||||||
|
`
|
|
@ -18,6 +18,9 @@ func Provider() terraform.ResourceProvider {
|
||||||
Description: "Fastly API Key from https://app.fastly.com/#account",
|
Description: "Fastly API Key from https://app.fastly.com/#account",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
DataSourcesMap: map[string]*schema.Resource{
|
||||||
|
"fastly_ip_ranges": dataSourceFastlyIPRanges(),
|
||||||
|
},
|
||||||
ResourcesMap: map[string]*schema.Resource{
|
ResourcesMap: map[string]*schema.Resource{
|
||||||
"fastly_service_v1": resourceServiceV1(),
|
"fastly_service_v1": resourceServiceV1(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -61,6 +61,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var InternalProviders = map[string]plugin.ProviderFunc{
|
var InternalProviders = map[string]plugin.ProviderFunc{
|
||||||
|
"archive": archiveprovider.Provider,
|
||||||
"atlas": atlasprovider.Provider,
|
"atlas": atlasprovider.Provider,
|
||||||
"aws": awsprovider.Provider,
|
"aws": awsprovider.Provider,
|
||||||
"azure": azureprovider.Provider,
|
"azure": azureprovider.Provider,
|
||||||
|
@ -105,7 +106,6 @@ var InternalProviders = map[string]plugin.ProviderFunc{
|
||||||
"ultradns": ultradnsprovider.Provider,
|
"ultradns": ultradnsprovider.Provider,
|
||||||
"vcd": vcdprovider.Provider,
|
"vcd": vcdprovider.Provider,
|
||||||
"vsphere": vsphereprovider.Provider,
|
"vsphere": vsphereprovider.Provider,
|
||||||
"archive": archiveprovider.Provider,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var InternalProvisioners = map[string]plugin.ProvisionerFunc{
|
var InternalProvisioners = map[string]plugin.ProvisionerFunc{
|
||||||
|
|
|
@ -27,9 +27,8 @@ will be rendered as a literal `${foo}`.
|
||||||
variable name. For example, `${var.foo}` will interpolate the
|
variable name. For example, `${var.foo}` will interpolate the
|
||||||
`foo` variable value. If the variable is a map, then you
|
`foo` variable value. If the variable is a map, then you
|
||||||
can reference static keys in the map with the syntax
|
can reference static keys in the map with the syntax
|
||||||
`var.MAP.KEY`. For example, `${var.amis.us-east-1}` would
|
`var.MAP["KEY"]`. For example, `${var.amis["us-east-1"]` would
|
||||||
get the value of the `us-east-1` key within the `amis` variable
|
get the value of the `us-east-1` key within the `amis` map variable.
|
||||||
that is a map.
|
|
||||||
|
|
||||||
**To reference attributes of your own resource**, the syntax is
|
**To reference attributes of your own resource**, the syntax is
|
||||||
`self.ATTRIBUTE`. For example `${self.private_ip_address}` will
|
`self.ATTRIBUTE`. For example `${self.private_ip_address}` will
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
---
|
||||||
|
layout: "aws"
|
||||||
|
page_title: "AWS: aws_ip_ranges"
|
||||||
|
sidebar_current: "docs-aws-datasource-ip_ranges"
|
||||||
|
description: |-
|
||||||
|
Get information on AWS IP ranges.
|
||||||
|
---
|
||||||
|
|
||||||
|
# aws\_ip_ranges
|
||||||
|
|
||||||
|
Use this data source to get the [IP ranges][1] of various AWS products and services.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
data "aws_ip_ranges" "european_ec2" {
|
||||||
|
regions = [ "eu-west-1", "eu-central-1" ]
|
||||||
|
services = [ "ec2" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group" "from_europe" {
|
||||||
|
|
||||||
|
name = "from_europe"
|
||||||
|
|
||||||
|
ingress {
|
||||||
|
from_port = "443"
|
||||||
|
to_port = "443"
|
||||||
|
protocol = "tcp"
|
||||||
|
cidr_blocks = [ "${data.aws_ip_ranges.european_ec2.blocks}" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tags {
|
||||||
|
CreateDate = "${data.aws_ip_ranges.european_ec2.create_date}"
|
||||||
|
SyncToken = "${data.aws_ip_ranges.european_ec2.sync_token}"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
* `regions` - (Optional) Filter IP ranges by regions (or include all regions, if
|
||||||
|
omitted). Valid items are `global` (for `cloudfront`) as well as all AWS regions
|
||||||
|
(e.g. `eu-central-1`)
|
||||||
|
|
||||||
|
* `services` - (Required) Filter IP ranges by services. Valid items are `amazon`
|
||||||
|
(for amazon.com), `cloudfront`, `ec2`, `route53` and `route53_healthchecks`.
|
||||||
|
|
||||||
|
~> **NOTE:** If the specified combination of regions and services does not yield any
|
||||||
|
CIDR blocks, Terraform will fail.
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
* `cidr_blocks` - The lexically ordered list of CIDR blocks.
|
||||||
|
* `create_date` - The publication time of the IP ranges (e.g. `2016-08-03-23-46-05`).
|
||||||
|
* `sync_token` - The publication time of the IP ranges, in Unix epoch time format
|
||||||
|
(e.g. `1470267965`).
|
||||||
|
|
||||||
|
[1]: http://docs.aws.amazon.com/general/latest/gr/aws-ip-ranges.html
|
|
@ -4,7 +4,7 @@ page_title: "AWS: aws_opsworks_permission"
|
||||||
sidebar_current: "docs-aws-resource-opsworks-permission"
|
sidebar_current: "docs-aws-resource-opsworks-permission"
|
||||||
description: |-
|
description: |-
|
||||||
Provides an OpsWorks permission resource.
|
Provides an OpsWorks permission resource.
|
||||||
-------------------------------------------
|
---
|
||||||
|
|
||||||
# aws\_opsworks\_permission
|
# aws\_opsworks\_permission
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
---
|
---
|
||||||
layout: "aws"
|
layout: "aws"
|
||||||
page_title: "AWS: aws_opsworks_user_profile_"
|
page_title: "AWS: aws_opsworks_user_profile"
|
||||||
sidebar_current: "docs-aws-resource-opsworks-user-profile"
|
sidebar_current: "docs-aws-resource-opsworks-user-profile"
|
||||||
description: |-
|
description: |-
|
||||||
Provides an OpsWorks User Profile resource.
|
Provides an OpsWorks User Profile resource.
|
||||||
---------------------------------------------
|
---
|
||||||
|
|
||||||
# aws\_opsworks\_user\_profile
|
# aws\_opsworks\_user\_profile
|
||||||
|
|
||||||
|
|
|
@ -173,6 +173,10 @@ The following arguments are supported:
|
||||||
* `logging` - (Optional) A settings of [bucket logging](https://docs.aws.amazon.com/AmazonS3/latest/UG/ManagingBucketLogging.html) (documented below).
|
* `logging` - (Optional) A settings of [bucket logging](https://docs.aws.amazon.com/AmazonS3/latest/UG/ManagingBucketLogging.html) (documented below).
|
||||||
* `lifecycle_rule` - (Optional) A configuration of [object lifecycle management](http://docs.aws.amazon.com/AmazonS3/latest/dev/object-lifecycle-mgmt.html) (documented below).
|
* `lifecycle_rule` - (Optional) A configuration of [object lifecycle management](http://docs.aws.amazon.com/AmazonS3/latest/dev/object-lifecycle-mgmt.html) (documented below).
|
||||||
* `acceleration_status` - (Optional) Sets the accelerate configuration of an existing bucket. Can be `Enabled` or `Suspended`.
|
* `acceleration_status` - (Optional) Sets the accelerate configuration of an existing bucket. Can be `Enabled` or `Suspended`.
|
||||||
|
* `request_payer` - (Optional) Specifies who should bear the cost of Amazon S3 data transfer.
|
||||||
|
Can be either `BucketOwner` or `Requester`. By default, the owner of the S3 bucket would incur
|
||||||
|
the costs of any data transfer. See [Requester Pays Buckets](http://docs.aws.amazon.com/AmazonS3/latest/dev/RequesterPaysBuckets.html)
|
||||||
|
developer guide for more information.
|
||||||
|
|
||||||
~> **NOTE:** You cannot use `acceleration_status` in `cn-north-1` or `us-gov-west-1`
|
~> **NOTE:** You cannot use `acceleration_status` in `cn-north-1` or `us-gov-west-1`
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ The following arguments are supported:
|
||||||
* `key` - (Required) The name of the object once it is in the bucket.
|
* `key` - (Required) The name of the object once it is in the bucket.
|
||||||
* `source` - (Required) The path to the source file being uploaded to the bucket.
|
* `source` - (Required) The path to the source file being uploaded to the bucket.
|
||||||
* `content` - (Required unless `source` given) The literal content being uploaded to the bucket.
|
* `content` - (Required unless `source` given) The literal content being uploaded to the bucket.
|
||||||
|
* `acl` - (Optional) The [canned ACL](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl) to apply. Defaults to "private".
|
||||||
* `cache_control` - (Optional) Specifies caching behavior along the request/reply chain Read [w3c cache_control](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9) for further details.
|
* `cache_control` - (Optional) Specifies caching behavior along the request/reply chain Read [w3c cache_control](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9) for further details.
|
||||||
* `content_disposition` - (Optional) Specifies presentational information for the object. Read [wc3 content_disposition](http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1) for further information.
|
* `content_disposition` - (Optional) Specifies presentational information for the object. Read [wc3 content_disposition](http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1) for further information.
|
||||||
* `content_encoding` - (Optional) Specifies what content encodings have been applied to the object and thus what decoding mechanisms must be applied to obtain the media-type referenced by the Content-Type header field. Read [w3c content encoding](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11) for further information.
|
* `content_encoding` - (Optional) Specifies what content encodings have been applied to the object and thus what decoding mechanisms must be applied to obtain the media-type referenced by the Content-Type header field. Read [w3c content encoding](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11) for further information.
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
---
|
||||||
|
layout: "fastly"
|
||||||
|
page_title: "Fastly: fastly_ip_ranges"
|
||||||
|
sidebar_current: "docs-fastly-datasource-ip_ranges"
|
||||||
|
description: |-
|
||||||
|
Get information on Fastly IP ranges.
|
||||||
|
---
|
||||||
|
|
||||||
|
# fastly\_ip_ranges
|
||||||
|
|
||||||
|
Use this data source to get the [IP ranges][1] of Fastly edge nodes.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
data "fastly_ip_ranges" "fastly" {
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group" "from_fastly" {
|
||||||
|
|
||||||
|
name = "from_fastly"
|
||||||
|
|
||||||
|
ingress {
|
||||||
|
from_port = "443"
|
||||||
|
to_port = "443"
|
||||||
|
protocol = "tcp"
|
||||||
|
cidr_blocks = [ "${data.fastly_ip_ranges.fastly.cidr_blocks}" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
* `cidr_blocks` - The lexically ordered list of CIDR blocks.
|
||||||
|
|
||||||
|
[1]: https://docs.fastly.com/guides/securing-communications/accessing-fastlys-ip-ranges
|
|
@ -51,7 +51,7 @@ The following arguments are supported:
|
||||||
Keystone service. By specifying a token, you do not have to
|
Keystone service. By specifying a token, you do not have to
|
||||||
specify a username/password combination, since the token was
|
specify a username/password combination, since the token was
|
||||||
already created by a username/password out of band of Terraform.
|
already created by a username/password out of band of Terraform.
|
||||||
If ommitted, the `OS_AUTH_TOKEN` environment variable is used.
|
If omitted, the `OS_AUTH_TOKEN` environment variable is used.
|
||||||
|
|
||||||
* `api_key` - (Optional; Required if not using `password`) An API Key
|
* `api_key` - (Optional; Required if not using `password`) An API Key
|
||||||
is issued by a cloud provider as alternative password. Unless
|
is issued by a cloud provider as alternative password. Unless
|
||||||
|
@ -144,6 +144,8 @@ variables must also be set:
|
||||||
|
|
||||||
* `OS_NETWORK_ID` - The UUID of a network in your test environment.
|
* `OS_NETWORK_ID` - The UUID of a network in your test environment.
|
||||||
|
|
||||||
|
* `OS_EXTGW_ID` - The UUID of the external gateway.
|
||||||
|
|
||||||
To make development easier, the `builtin/providers/openstack/devstack/deploy.sh`
|
To make development easier, the `builtin/providers/openstack/devstack/deploy.sh`
|
||||||
script will assist in installing and configuring a standardized
|
script will assist in installing and configuring a standardized
|
||||||
[DevStack](http://docs.openstack.org/developer/devstack/) environment along with
|
[DevStack](http://docs.openstack.org/developer/devstack/) environment along with
|
||||||
|
|
|
@ -15,6 +15,7 @@ Provides a PowerDNS record resource.
|
||||||
Note that PowerDNS internally lowercases certain records (e.g. CNAME and AAAA), which can lead to resources being marked for a change in every singe plan.
|
Note that PowerDNS internally lowercases certain records (e.g. CNAME and AAAA), which can lead to resources being marked for a change in every singe plan.
|
||||||
|
|
||||||
For the v1 API (PowerDNS version 4):
|
For the v1 API (PowerDNS version 4):
|
||||||
|
|
||||||
```
|
```
|
||||||
# Add a record to the zone
|
# Add a record to the zone
|
||||||
resource "powerdns_record" "foobar" {
|
resource "powerdns_record" "foobar" {
|
||||||
|
@ -27,6 +28,7 @@ resource "powerdns_record" "foobar" {
|
||||||
```
|
```
|
||||||
|
|
||||||
For the legacy API (PowerDNS version 3.4):
|
For the legacy API (PowerDNS version 3.4):
|
||||||
|
|
||||||
```
|
```
|
||||||
# Add a record to the zone
|
# Add a record to the zone
|
||||||
resource "powerdns_record" "foobar" {
|
resource "powerdns_record" "foobar" {
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
<li<%= sidebar_current("docs-aws-datasource-iam-policy-document") %>>
|
<li<%= sidebar_current("docs-aws-datasource-iam-policy-document") %>>
|
||||||
<a href="/docs/providers/aws/d/iam_policy_document.html">aws_iam_policy_document</a>
|
<a href="/docs/providers/aws/d/iam_policy_document.html">aws_iam_policy_document</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li<%= sidebar_current("docs-aws-datasource-ip_ranges") %>>
|
||||||
|
<a href="/docs/providers/aws/d/ip_ranges.html">aws_ip_ranges</a>
|
||||||
|
</li>
|
||||||
<li<%= sidebar_current("docs-aws-datasource-s3-bucket-object") %>>
|
<li<%= sidebar_current("docs-aws-datasource-s3-bucket-object") %>>
|
||||||
<a href="/docs/providers/aws/d/s3_bucket_object.html">aws_s3_bucket_object</a>
|
<a href="/docs/providers/aws/d/s3_bucket_object.html">aws_s3_bucket_object</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -567,6 +570,10 @@
|
||||||
<a href="#">OpsWorks Resources</a>
|
<a href="#">OpsWorks Resources</a>
|
||||||
<ul class="nav nav-visible">
|
<ul class="nav nav-visible">
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-aws-resource-opsworks-application") %>>
|
||||||
|
<a href="/docs/providers/aws/r/opsworks_application.html">aws_opsworks_application</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-aws-resource-opsworks-custom-layer") %>>
|
<li<%= sidebar_current("docs-aws-resource-opsworks-custom-layer") %>>
|
||||||
<a href="/docs/providers/aws/r/opsworks_custom_layer.html">aws_opsworks_custom_layer</a>
|
<a href="/docs/providers/aws/r/opsworks_custom_layer.html">aws_opsworks_custom_layer</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -599,6 +606,10 @@
|
||||||
<a href="/docs/providers/aws/r/opsworks_nodejs_app_layer.html">aws_opsworks_nodejs_app_layer</a>
|
<a href="/docs/providers/aws/r/opsworks_nodejs_app_layer.html">aws_opsworks_nodejs_app_layer</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-aws-resource-opsworks-permission") %>>
|
||||||
|
<a href="/docs/providers/aws/r/opsworks_permission.html">aws_opsworks_permission</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-aws-resource-opsworks-php-app-layer") %>>
|
<li<%= sidebar_current("docs-aws-resource-opsworks-php-app-layer") %>>
|
||||||
<a href="/docs/providers/aws/r/opsworks_php_app_layer.html">aws_opsworks_php_app_layer</a>
|
<a href="/docs/providers/aws/r/opsworks_php_app_layer.html">aws_opsworks_php_app_layer</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -615,8 +626,8 @@
|
||||||
<a href="/docs/providers/aws/r/opsworks_static_web_layer.html">aws_opsworks_static_web_layer</a>
|
<a href="/docs/providers/aws/r/opsworks_static_web_layer.html">aws_opsworks_static_web_layer</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-aws-resource-opsworks-application") %>>
|
<li<%= sidebar_current("docs-aws-resource-opsworks-user-profile") %>>
|
||||||
<a href="/docs/providers/aws/r/opsworks_application.html">aws_opsworks_application</a>
|
<a href="/docs/providers/aws/r/opsworks_user_profile.html">aws_opsworks_user_profile</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -10,6 +10,15 @@
|
||||||
<a href="/docs/providers/fastly/index.html">Fastly Provider</a>
|
<a href="/docs/providers/fastly/index.html">Fastly Provider</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current(/^docs-fastly-datasource/) %>>
|
||||||
|
<a href="#">Data Sources</a>
|
||||||
|
<ul class="nav nav-visible">
|
||||||
|
<li<%= sidebar_current("docs-fastly-datasource-ip_ranges") %>>
|
||||||
|
<a href="/docs/providers/fastly/d/ip_ranges.html">fastly_ip_ranges</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current(/^docs-fastly-resource/) %>>
|
<li<%= sidebar_current(/^docs-fastly-resource/) %>>
|
||||||
<a href="#">Resources</a>
|
<a href="#">Resources</a>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue