github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_s3_bucket.go (about)

     1  package aws
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"log"
     8  	"net/url"
     9  	"regexp"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/aws/aws-sdk-go/aws"
    14  	"github.com/aws/aws-sdk-go/aws/awserr"
    15  	"github.com/aws/aws-sdk-go/service/s3"
    16  	"github.com/hashicorp/errwrap"
    17  	"github.com/hashicorp/terraform/helper/hashcode"
    18  	"github.com/hashicorp/terraform/helper/resource"
    19  	"github.com/hashicorp/terraform/helper/schema"
    20  )
    21  
    22  func resourceAwsS3Bucket() *schema.Resource {
    23  	return &schema.Resource{
    24  		Create: resourceAwsS3BucketCreate,
    25  		Read:   resourceAwsS3BucketRead,
    26  		Update: resourceAwsS3BucketUpdate,
    27  		Delete: resourceAwsS3BucketDelete,
    28  		Importer: &schema.ResourceImporter{
    29  			State: resourceAwsS3BucketImportState,
    30  		},
    31  
    32  		Schema: map[string]*schema.Schema{
    33  			"bucket": {
    34  				Type:          schema.TypeString,
    35  				Optional:      true,
    36  				Computed:      true,
    37  				ForceNew:      true,
    38  				ConflictsWith: []string{"bucket_prefix"},
    39  			},
    40  			"bucket_prefix": {
    41  				Type:     schema.TypeString,
    42  				Optional: true,
    43  				ForceNew: true,
    44  			},
    45  
    46  			"bucket_domain_name": {
    47  				Type:     schema.TypeString,
    48  				Computed: true,
    49  			},
    50  
    51  			"arn": {
    52  				Type:     schema.TypeString,
    53  				Optional: true,
    54  				Computed: true,
    55  			},
    56  
    57  			"acl": {
    58  				Type:     schema.TypeString,
    59  				Default:  "private",
    60  				Optional: true,
    61  			},
    62  
    63  			"policy": {
    64  				Type:             schema.TypeString,
    65  				Optional:         true,
    66  				ValidateFunc:     validateJsonString,
    67  				DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs,
    68  			},
    69  
    70  			"cors_rule": {
    71  				Type:     schema.TypeList,
    72  				Optional: true,
    73  				Elem: &schema.Resource{
    74  					Schema: map[string]*schema.Schema{
    75  						"allowed_headers": {
    76  							Type:     schema.TypeList,
    77  							Optional: true,
    78  							Elem:     &schema.Schema{Type: schema.TypeString},
    79  						},
    80  						"allowed_methods": {
    81  							Type:     schema.TypeList,
    82  							Required: true,
    83  							Elem:     &schema.Schema{Type: schema.TypeString},
    84  						},
    85  						"allowed_origins": {
    86  							Type:     schema.TypeList,
    87  							Required: true,
    88  							Elem:     &schema.Schema{Type: schema.TypeString},
    89  						},
    90  						"expose_headers": {
    91  							Type:     schema.TypeList,
    92  							Optional: true,
    93  							Elem:     &schema.Schema{Type: schema.TypeString},
    94  						},
    95  						"max_age_seconds": {
    96  							Type:     schema.TypeInt,
    97  							Optional: true,
    98  						},
    99  					},
   100  				},
   101  			},
   102  
   103  			"website": {
   104  				Type:     schema.TypeList,
   105  				Optional: true,
   106  				Elem: &schema.Resource{
   107  					Schema: map[string]*schema.Schema{
   108  						"index_document": {
   109  							Type:     schema.TypeString,
   110  							Optional: true,
   111  						},
   112  
   113  						"error_document": {
   114  							Type:     schema.TypeString,
   115  							Optional: true,
   116  						},
   117  
   118  						"redirect_all_requests_to": {
   119  							Type: schema.TypeString,
   120  							ConflictsWith: []string{
   121  								"website.0.index_document",
   122  								"website.0.error_document",
   123  								"website.0.routing_rules",
   124  							},
   125  							Optional: true,
   126  						},
   127  
   128  						"routing_rules": {
   129  							Type:         schema.TypeString,
   130  							Optional:     true,
   131  							ValidateFunc: validateJsonString,
   132  							StateFunc: func(v interface{}) string {
   133  								json, _ := normalizeJsonString(v)
   134  								return json
   135  							},
   136  						},
   137  					},
   138  				},
   139  			},
   140  
   141  			"hosted_zone_id": {
   142  				Type:     schema.TypeString,
   143  				Optional: true,
   144  				Computed: true,
   145  			},
   146  
   147  			"region": {
   148  				Type:     schema.TypeString,
   149  				Optional: true,
   150  				Computed: true,
   151  			},
   152  			"website_endpoint": {
   153  				Type:     schema.TypeString,
   154  				Optional: true,
   155  				Computed: true,
   156  			},
   157  			"website_domain": {
   158  				Type:     schema.TypeString,
   159  				Optional: true,
   160  				Computed: true,
   161  			},
   162  
   163  			"versioning": {
   164  				Type:     schema.TypeList,
   165  				Optional: true,
   166  				Computed: true,
   167  				MaxItems: 1,
   168  				Elem: &schema.Resource{
   169  					Schema: map[string]*schema.Schema{
   170  						"enabled": {
   171  							Type:     schema.TypeBool,
   172  							Optional: true,
   173  							Default:  false,
   174  						},
   175  						"mfa_delete": {
   176  							Type:     schema.TypeBool,
   177  							Optional: true,
   178  							Default:  false,
   179  						},
   180  					},
   181  				},
   182  			},
   183  
   184  			"logging": {
   185  				Type:     schema.TypeSet,
   186  				Optional: true,
   187  				Elem: &schema.Resource{
   188  					Schema: map[string]*schema.Schema{
   189  						"target_bucket": {
   190  							Type:     schema.TypeString,
   191  							Required: true,
   192  						},
   193  						"target_prefix": {
   194  							Type:     schema.TypeString,
   195  							Optional: true,
   196  						},
   197  					},
   198  				},
   199  				Set: func(v interface{}) int {
   200  					var buf bytes.Buffer
   201  					m := v.(map[string]interface{})
   202  					buf.WriteString(fmt.Sprintf("%s-", m["target_bucket"]))
   203  					buf.WriteString(fmt.Sprintf("%s-", m["target_prefix"]))
   204  					return hashcode.String(buf.String())
   205  				},
   206  			},
   207  
   208  			"lifecycle_rule": {
   209  				Type:     schema.TypeList,
   210  				Optional: true,
   211  				Elem: &schema.Resource{
   212  					Schema: map[string]*schema.Schema{
   213  						"id": {
   214  							Type:         schema.TypeString,
   215  							Optional:     true,
   216  							Computed:     true,
   217  							ValidateFunc: validateS3BucketLifecycleRuleId,
   218  						},
   219  						"prefix": {
   220  							Type:     schema.TypeString,
   221  							Required: true,
   222  						},
   223  						"enabled": {
   224  							Type:     schema.TypeBool,
   225  							Required: true,
   226  						},
   227  						"abort_incomplete_multipart_upload_days": {
   228  							Type:     schema.TypeInt,
   229  							Optional: true,
   230  						},
   231  						"expiration": {
   232  							Type:     schema.TypeSet,
   233  							Optional: true,
   234  							Set:      expirationHash,
   235  							Elem: &schema.Resource{
   236  								Schema: map[string]*schema.Schema{
   237  									"date": {
   238  										Type:         schema.TypeString,
   239  										Optional:     true,
   240  										ValidateFunc: validateS3BucketLifecycleTimestamp,
   241  									},
   242  									"days": {
   243  										Type:     schema.TypeInt,
   244  										Optional: true,
   245  									},
   246  									"expired_object_delete_marker": {
   247  										Type:     schema.TypeBool,
   248  										Optional: true,
   249  									},
   250  								},
   251  							},
   252  						},
   253  						"noncurrent_version_expiration": {
   254  							Type:     schema.TypeSet,
   255  							Optional: true,
   256  							Set:      expirationHash,
   257  							Elem: &schema.Resource{
   258  								Schema: map[string]*schema.Schema{
   259  									"days": {
   260  										Type:     schema.TypeInt,
   261  										Optional: true,
   262  									},
   263  								},
   264  							},
   265  						},
   266  						"transition": {
   267  							Type:     schema.TypeSet,
   268  							Optional: true,
   269  							Set:      transitionHash,
   270  							Elem: &schema.Resource{
   271  								Schema: map[string]*schema.Schema{
   272  									"date": {
   273  										Type:         schema.TypeString,
   274  										Optional:     true,
   275  										ValidateFunc: validateS3BucketLifecycleTimestamp,
   276  									},
   277  									"days": {
   278  										Type:     schema.TypeInt,
   279  										Optional: true,
   280  									},
   281  									"storage_class": {
   282  										Type:         schema.TypeString,
   283  										Required:     true,
   284  										ValidateFunc: validateS3BucketLifecycleStorageClass,
   285  									},
   286  								},
   287  							},
   288  						},
   289  						"noncurrent_version_transition": {
   290  							Type:     schema.TypeSet,
   291  							Optional: true,
   292  							Set:      transitionHash,
   293  							Elem: &schema.Resource{
   294  								Schema: map[string]*schema.Schema{
   295  									"days": {
   296  										Type:     schema.TypeInt,
   297  										Optional: true,
   298  									},
   299  									"storage_class": {
   300  										Type:         schema.TypeString,
   301  										Required:     true,
   302  										ValidateFunc: validateS3BucketLifecycleStorageClass,
   303  									},
   304  								},
   305  							},
   306  						},
   307  					},
   308  				},
   309  			},
   310  
   311  			"force_destroy": {
   312  				Type:     schema.TypeBool,
   313  				Optional: true,
   314  				Default:  false,
   315  			},
   316  
   317  			"acceleration_status": {
   318  				Type:         schema.TypeString,
   319  				Optional:     true,
   320  				Computed:     true,
   321  				ValidateFunc: validateS3BucketAccelerationStatus,
   322  			},
   323  
   324  			"request_payer": {
   325  				Type:         schema.TypeString,
   326  				Optional:     true,
   327  				Computed:     true,
   328  				ValidateFunc: validateS3BucketRequestPayerType,
   329  			},
   330  
   331  			"replication_configuration": {
   332  				Type:     schema.TypeList,
   333  				Optional: true,
   334  				MaxItems: 1,
   335  				Elem: &schema.Resource{
   336  					Schema: map[string]*schema.Schema{
   337  						"role": {
   338  							Type:     schema.TypeString,
   339  							Required: true,
   340  						},
   341  						"rules": {
   342  							Type:     schema.TypeSet,
   343  							Required: true,
   344  							Set:      rulesHash,
   345  							Elem: &schema.Resource{
   346  								Schema: map[string]*schema.Schema{
   347  									"id": {
   348  										Type:         schema.TypeString,
   349  										Optional:     true,
   350  										ValidateFunc: validateS3BucketReplicationRuleId,
   351  									},
   352  									"destination": {
   353  										Type:     schema.TypeSet,
   354  										MaxItems: 1,
   355  										MinItems: 1,
   356  										Required: true,
   357  										Set:      destinationHash,
   358  										Elem: &schema.Resource{
   359  											Schema: map[string]*schema.Schema{
   360  												"bucket": {
   361  													Type:         schema.TypeString,
   362  													Required:     true,
   363  													ValidateFunc: validateArn,
   364  												},
   365  												"storage_class": {
   366  													Type:         schema.TypeString,
   367  													Optional:     true,
   368  													ValidateFunc: validateS3BucketReplicationDestinationStorageClass,
   369  												},
   370  											},
   371  										},
   372  									},
   373  									"prefix": {
   374  										Type:         schema.TypeString,
   375  										Required:     true,
   376  										ValidateFunc: validateS3BucketReplicationRulePrefix,
   377  									},
   378  									"status": {
   379  										Type:         schema.TypeString,
   380  										Required:     true,
   381  										ValidateFunc: validateS3BucketReplicationRuleStatus,
   382  									},
   383  								},
   384  							},
   385  						},
   386  					},
   387  				},
   388  			},
   389  
   390  			"tags": tagsSchema(),
   391  		},
   392  	}
   393  }
   394  
   395  func resourceAwsS3BucketCreate(d *schema.ResourceData, meta interface{}) error {
   396  	s3conn := meta.(*AWSClient).s3conn
   397  
   398  	// Get the bucket and acl
   399  	var bucket string
   400  	if v, ok := d.GetOk("bucket"); ok {
   401  		bucket = v.(string)
   402  	} else if v, ok := d.GetOk("bucket_prefix"); ok {
   403  		bucket = resource.PrefixedUniqueId(v.(string))
   404  	} else {
   405  		bucket = resource.UniqueId()
   406  	}
   407  	d.Set("bucket", bucket)
   408  	acl := d.Get("acl").(string)
   409  
   410  	log.Printf("[DEBUG] S3 bucket create: %s, ACL: %s", bucket, acl)
   411  
   412  	req := &s3.CreateBucketInput{
   413  		Bucket: aws.String(bucket),
   414  		ACL:    aws.String(acl),
   415  	}
   416  
   417  	var awsRegion string
   418  	if region, ok := d.GetOk("region"); ok {
   419  		awsRegion = region.(string)
   420  	} else {
   421  		awsRegion = meta.(*AWSClient).region
   422  	}
   423  	log.Printf("[DEBUG] S3 bucket create: %s, using region: %s", bucket, awsRegion)
   424  
   425  	// Special case us-east-1 region and do not set the LocationConstraint.
   426  	// See "Request Elements: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUT.html
   427  	if awsRegion != "us-east-1" {
   428  		req.CreateBucketConfiguration = &s3.CreateBucketConfiguration{
   429  			LocationConstraint: aws.String(awsRegion),
   430  		}
   431  	}
   432  
   433  	if err := validateS3BucketName(bucket, awsRegion); err != nil {
   434  		return fmt.Errorf("Error validating S3 bucket name: %s", err)
   435  	}
   436  
   437  	err := resource.Retry(5*time.Minute, func() *resource.RetryError {
   438  		log.Printf("[DEBUG] Trying to create new S3 bucket: %q", bucket)
   439  		_, err := s3conn.CreateBucket(req)
   440  		if awsErr, ok := err.(awserr.Error); ok {
   441  			if awsErr.Code() == "OperationAborted" {
   442  				log.Printf("[WARN] Got an error while trying to create S3 bucket %s: %s", bucket, err)
   443  				return resource.RetryableError(
   444  					fmt.Errorf("[WARN] Error creating S3 bucket %s, retrying: %s",
   445  						bucket, err))
   446  			}
   447  		}
   448  		if err != nil {
   449  			return resource.NonRetryableError(err)
   450  		}
   451  
   452  		return nil
   453  	})
   454  
   455  	if err != nil {
   456  		return fmt.Errorf("Error creating S3 bucket: %s", err)
   457  	}
   458  
   459  	// Assign the bucket name as the resource ID
   460  	d.SetId(bucket)
   461  
   462  	return resourceAwsS3BucketUpdate(d, meta)
   463  }
   464  
   465  func resourceAwsS3BucketUpdate(d *schema.ResourceData, meta interface{}) error {
   466  	s3conn := meta.(*AWSClient).s3conn
   467  	if err := setTagsS3(s3conn, d); err != nil {
   468  		return fmt.Errorf("%q: %s", d.Get("bucket").(string), err)
   469  	}
   470  
   471  	if d.HasChange("policy") {
   472  		if err := resourceAwsS3BucketPolicyUpdate(s3conn, d); err != nil {
   473  			return err
   474  		}
   475  	}
   476  
   477  	if d.HasChange("cors_rule") {
   478  		if err := resourceAwsS3BucketCorsUpdate(s3conn, d); err != nil {
   479  			return err
   480  		}
   481  	}
   482  
   483  	if d.HasChange("website") {
   484  		if err := resourceAwsS3BucketWebsiteUpdate(s3conn, d); err != nil {
   485  			return err
   486  		}
   487  	}
   488  
   489  	if d.HasChange("versioning") {
   490  		if err := resourceAwsS3BucketVersioningUpdate(s3conn, d); err != nil {
   491  			return err
   492  		}
   493  	}
   494  	if d.HasChange("acl") {
   495  		if err := resourceAwsS3BucketAclUpdate(s3conn, d); err != nil {
   496  			return err
   497  		}
   498  	}
   499  
   500  	if d.HasChange("logging") {
   501  		if err := resourceAwsS3BucketLoggingUpdate(s3conn, d); err != nil {
   502  			return err
   503  		}
   504  	}
   505  
   506  	if d.HasChange("lifecycle_rule") {
   507  		if err := resourceAwsS3BucketLifecycleUpdate(s3conn, d); err != nil {
   508  			return err
   509  		}
   510  	}
   511  
   512  	if d.HasChange("acceleration_status") {
   513  		if err := resourceAwsS3BucketAccelerationUpdate(s3conn, d); err != nil {
   514  			return err
   515  		}
   516  	}
   517  
   518  	if d.HasChange("request_payer") {
   519  		if err := resourceAwsS3BucketRequestPayerUpdate(s3conn, d); err != nil {
   520  			return err
   521  		}
   522  	}
   523  
   524  	if d.HasChange("replication_configuration") {
   525  		if err := resourceAwsS3BucketReplicationConfigurationUpdate(s3conn, d); err != nil {
   526  			return err
   527  		}
   528  	}
   529  
   530  	return resourceAwsS3BucketRead(d, meta)
   531  }
   532  
   533  func resourceAwsS3BucketRead(d *schema.ResourceData, meta interface{}) error {
   534  	s3conn := meta.(*AWSClient).s3conn
   535  
   536  	var err error
   537  	_, err = s3conn.HeadBucket(&s3.HeadBucketInput{
   538  		Bucket: aws.String(d.Id()),
   539  	})
   540  	if err != nil {
   541  		if awsError, ok := err.(awserr.RequestFailure); ok && awsError.StatusCode() == 404 {
   542  			log.Printf("[WARN] S3 Bucket (%s) not found, error code (404)", d.Id())
   543  			d.SetId("")
   544  			return nil
   545  		} else {
   546  			// some of the AWS SDK's errors can be empty strings, so let's add
   547  			// some additional context.
   548  			return fmt.Errorf("error reading S3 bucket \"%s\": %s", d.Id(), err)
   549  		}
   550  	}
   551  
   552  	// In the import case, we won't have this
   553  	if _, ok := d.GetOk("bucket"); !ok {
   554  		d.Set("bucket", d.Id())
   555  	}
   556  
   557  	d.Set("bucket_domain_name", bucketDomainName(d.Get("bucket").(string)))
   558  
   559  	// Read the policy
   560  	if _, ok := d.GetOk("policy"); ok {
   561  		pol, err := s3conn.GetBucketPolicy(&s3.GetBucketPolicyInput{
   562  			Bucket: aws.String(d.Id()),
   563  		})
   564  		log.Printf("[DEBUG] S3 bucket: %s, read policy: %v", d.Id(), pol)
   565  		if err != nil {
   566  			if err := d.Set("policy", ""); err != nil {
   567  				return err
   568  			}
   569  		} else {
   570  			if v := pol.Policy; v == nil {
   571  				if err := d.Set("policy", ""); err != nil {
   572  					return err
   573  				}
   574  			} else {
   575  				policy, err := normalizeJsonString(*v)
   576  				if err != nil {
   577  					return errwrap.Wrapf("policy contains an invalid JSON: {{err}}", err)
   578  				}
   579  				d.Set("policy", policy)
   580  			}
   581  		}
   582  	}
   583  
   584  	// Read the CORS
   585  	cors, err := s3conn.GetBucketCors(&s3.GetBucketCorsInput{
   586  		Bucket: aws.String(d.Id()),
   587  	})
   588  	if err != nil {
   589  		// An S3 Bucket might not have CORS configuration set.
   590  		if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() != "NoSuchCORSConfiguration" {
   591  			return err
   592  		}
   593  		log.Printf("[WARN] S3 bucket: %s, no CORS configuration could be found.", d.Id())
   594  	}
   595  	log.Printf("[DEBUG] S3 bucket: %s, read CORS: %v", d.Id(), cors)
   596  	if cors.CORSRules != nil {
   597  		rules := make([]map[string]interface{}, 0, len(cors.CORSRules))
   598  		for _, ruleObject := range cors.CORSRules {
   599  			rule := make(map[string]interface{})
   600  			rule["allowed_headers"] = flattenStringList(ruleObject.AllowedHeaders)
   601  			rule["allowed_methods"] = flattenStringList(ruleObject.AllowedMethods)
   602  			rule["allowed_origins"] = flattenStringList(ruleObject.AllowedOrigins)
   603  			// Both the "ExposeHeaders" and "MaxAgeSeconds" might not be set.
   604  			if ruleObject.AllowedOrigins != nil {
   605  				rule["expose_headers"] = flattenStringList(ruleObject.ExposeHeaders)
   606  			}
   607  			if ruleObject.MaxAgeSeconds != nil {
   608  				rule["max_age_seconds"] = int(*ruleObject.MaxAgeSeconds)
   609  			}
   610  			rules = append(rules, rule)
   611  		}
   612  		if err := d.Set("cors_rule", rules); err != nil {
   613  			return err
   614  		}
   615  	}
   616  
   617  	// Read the website configuration
   618  	ws, err := s3conn.GetBucketWebsite(&s3.GetBucketWebsiteInput{
   619  		Bucket: aws.String(d.Id()),
   620  	})
   621  	var websites []map[string]interface{}
   622  	if err == nil {
   623  		w := make(map[string]interface{})
   624  
   625  		if v := ws.IndexDocument; v != nil {
   626  			w["index_document"] = *v.Suffix
   627  		}
   628  
   629  		if v := ws.ErrorDocument; v != nil {
   630  			w["error_document"] = *v.Key
   631  		}
   632  
   633  		if v := ws.RedirectAllRequestsTo; v != nil {
   634  			if v.Protocol == nil {
   635  				w["redirect_all_requests_to"] = *v.HostName
   636  			} else {
   637  				var host string
   638  				var path string
   639  				parsedHostName, err := url.Parse(*v.HostName)
   640  				if err == nil {
   641  					host = parsedHostName.Host
   642  					path = parsedHostName.Path
   643  				} else {
   644  					host = *v.HostName
   645  					path = ""
   646  				}
   647  
   648  				w["redirect_all_requests_to"] = (&url.URL{
   649  					Host:   host,
   650  					Path:   path,
   651  					Scheme: *v.Protocol,
   652  				}).String()
   653  			}
   654  		}
   655  
   656  		if v := ws.RoutingRules; v != nil {
   657  			rr, err := normalizeRoutingRules(v)
   658  			if err != nil {
   659  				return fmt.Errorf("Error while marshaling routing rules: %s", err)
   660  			}
   661  			w["routing_rules"] = rr
   662  		}
   663  
   664  		websites = append(websites, w)
   665  	}
   666  	if err := d.Set("website", websites); err != nil {
   667  		return err
   668  	}
   669  
   670  	// Read the versioning configuration
   671  	versioning, err := s3conn.GetBucketVersioning(&s3.GetBucketVersioningInput{
   672  		Bucket: aws.String(d.Id()),
   673  	})
   674  	if err != nil {
   675  		return err
   676  	}
   677  	log.Printf("[DEBUG] S3 Bucket: %s, versioning: %v", d.Id(), versioning)
   678  	if versioning != nil {
   679  		vcl := make([]map[string]interface{}, 0, 1)
   680  		vc := make(map[string]interface{})
   681  		if versioning.Status != nil && *versioning.Status == s3.BucketVersioningStatusEnabled {
   682  			vc["enabled"] = true
   683  		} else {
   684  			vc["enabled"] = false
   685  		}
   686  
   687  		if versioning.MFADelete != nil && *versioning.MFADelete == s3.MFADeleteEnabled {
   688  			vc["mfa_delete"] = true
   689  		} else {
   690  			vc["mfa_delete"] = false
   691  		}
   692  		vcl = append(vcl, vc)
   693  		if err := d.Set("versioning", vcl); err != nil {
   694  			return err
   695  		}
   696  	}
   697  
   698  	// Read the acceleration status
   699  	accelerate, err := s3conn.GetBucketAccelerateConfiguration(&s3.GetBucketAccelerateConfigurationInput{
   700  		Bucket: aws.String(d.Id()),
   701  	})
   702  	if err != nil {
   703  		// Amazon S3 Transfer Acceleration might not be supported in the
   704  		// given region, for example, China (Beijing) and the Government
   705  		// Cloud does not support this feature at the moment.
   706  		if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() != "UnsupportedArgument" {
   707  			return err
   708  		}
   709  
   710  		var awsRegion string
   711  		if region, ok := d.GetOk("region"); ok {
   712  			awsRegion = region.(string)
   713  		} else {
   714  			awsRegion = meta.(*AWSClient).region
   715  		}
   716  
   717  		log.Printf("[WARN] S3 bucket: %s, the S3 Transfer Acceleration is not supported in the region: %s", d.Id(), awsRegion)
   718  	} else {
   719  		log.Printf("[DEBUG] S3 bucket: %s, read Acceleration: %v", d.Id(), accelerate)
   720  		d.Set("acceleration_status", accelerate.Status)
   721  	}
   722  
   723  	// Read the request payer configuration.
   724  	payer, err := s3conn.GetBucketRequestPayment(&s3.GetBucketRequestPaymentInput{
   725  		Bucket: aws.String(d.Id()),
   726  	})
   727  	if err != nil {
   728  		return err
   729  	}
   730  	log.Printf("[DEBUG] S3 Bucket: %s, read request payer: %v", d.Id(), payer)
   731  	if payer.Payer != nil {
   732  		if err := d.Set("request_payer", *payer.Payer); err != nil {
   733  			return err
   734  		}
   735  	}
   736  
   737  	// Read the logging configuration
   738  	logging, err := s3conn.GetBucketLogging(&s3.GetBucketLoggingInput{
   739  		Bucket: aws.String(d.Id()),
   740  	})
   741  	if err != nil {
   742  		return err
   743  	}
   744  
   745  	log.Printf("[DEBUG] S3 Bucket: %s, logging: %v", d.Id(), logging)
   746  	lcl := make([]map[string]interface{}, 0, 1)
   747  	if v := logging.LoggingEnabled; v != nil {
   748  		lc := make(map[string]interface{})
   749  		if *v.TargetBucket != "" {
   750  			lc["target_bucket"] = *v.TargetBucket
   751  		}
   752  		if *v.TargetPrefix != "" {
   753  			lc["target_prefix"] = *v.TargetPrefix
   754  		}
   755  		lcl = append(lcl, lc)
   756  	}
   757  	if err := d.Set("logging", lcl); err != nil {
   758  		return err
   759  	}
   760  
   761  	// Read the lifecycle configuration
   762  	lifecycle, err := s3conn.GetBucketLifecycleConfiguration(&s3.GetBucketLifecycleConfigurationInput{
   763  		Bucket: aws.String(d.Id()),
   764  	})
   765  	if err != nil {
   766  		if awsError, ok := err.(awserr.RequestFailure); ok && awsError.StatusCode() != 404 {
   767  			return err
   768  		}
   769  	}
   770  	log.Printf("[DEBUG] S3 Bucket: %s, lifecycle: %v", d.Id(), lifecycle)
   771  	if len(lifecycle.Rules) > 0 {
   772  		rules := make([]map[string]interface{}, 0, len(lifecycle.Rules))
   773  
   774  		for _, lifecycleRule := range lifecycle.Rules {
   775  			rule := make(map[string]interface{})
   776  
   777  			// ID
   778  			if lifecycleRule.ID != nil && *lifecycleRule.ID != "" {
   779  				rule["id"] = *lifecycleRule.ID
   780  			}
   781  			// Prefix
   782  			if lifecycleRule.Prefix != nil && *lifecycleRule.Prefix != "" {
   783  				rule["prefix"] = *lifecycleRule.Prefix
   784  			}
   785  			// Enabled
   786  			if lifecycleRule.Status != nil {
   787  				if *lifecycleRule.Status == s3.ExpirationStatusEnabled {
   788  					rule["enabled"] = true
   789  				} else {
   790  					rule["enabled"] = false
   791  				}
   792  			}
   793  
   794  			// AbortIncompleteMultipartUploadDays
   795  			if lifecycleRule.AbortIncompleteMultipartUpload != nil {
   796  				if lifecycleRule.AbortIncompleteMultipartUpload.DaysAfterInitiation != nil {
   797  					rule["abort_incomplete_multipart_upload_days"] = int(*lifecycleRule.AbortIncompleteMultipartUpload.DaysAfterInitiation)
   798  				}
   799  			}
   800  
   801  			// expiration
   802  			if lifecycleRule.Expiration != nil {
   803  				e := make(map[string]interface{})
   804  				if lifecycleRule.Expiration.Date != nil {
   805  					e["date"] = (*lifecycleRule.Expiration.Date).Format("2006-01-02")
   806  				}
   807  				if lifecycleRule.Expiration.Days != nil {
   808  					e["days"] = int(*lifecycleRule.Expiration.Days)
   809  				}
   810  				if lifecycleRule.Expiration.ExpiredObjectDeleteMarker != nil {
   811  					e["expired_object_delete_marker"] = *lifecycleRule.Expiration.ExpiredObjectDeleteMarker
   812  				}
   813  				rule["expiration"] = schema.NewSet(expirationHash, []interface{}{e})
   814  			}
   815  			// noncurrent_version_expiration
   816  			if lifecycleRule.NoncurrentVersionExpiration != nil {
   817  				e := make(map[string]interface{})
   818  				if lifecycleRule.NoncurrentVersionExpiration.NoncurrentDays != nil {
   819  					e["days"] = int(*lifecycleRule.NoncurrentVersionExpiration.NoncurrentDays)
   820  				}
   821  				rule["noncurrent_version_expiration"] = schema.NewSet(expirationHash, []interface{}{e})
   822  			}
   823  			//// transition
   824  			if len(lifecycleRule.Transitions) > 0 {
   825  				transitions := make([]interface{}, 0, len(lifecycleRule.Transitions))
   826  				for _, v := range lifecycleRule.Transitions {
   827  					t := make(map[string]interface{})
   828  					if v.Date != nil {
   829  						t["date"] = (*v.Date).Format("2006-01-02")
   830  					}
   831  					if v.Days != nil {
   832  						t["days"] = int(*v.Days)
   833  					}
   834  					if v.StorageClass != nil {
   835  						t["storage_class"] = *v.StorageClass
   836  					}
   837  					transitions = append(transitions, t)
   838  				}
   839  				rule["transition"] = schema.NewSet(transitionHash, transitions)
   840  			}
   841  			// noncurrent_version_transition
   842  			if len(lifecycleRule.NoncurrentVersionTransitions) > 0 {
   843  				transitions := make([]interface{}, 0, len(lifecycleRule.NoncurrentVersionTransitions))
   844  				for _, v := range lifecycleRule.NoncurrentVersionTransitions {
   845  					t := make(map[string]interface{})
   846  					if v.NoncurrentDays != nil {
   847  						t["days"] = int(*v.NoncurrentDays)
   848  					}
   849  					if v.StorageClass != nil {
   850  						t["storage_class"] = *v.StorageClass
   851  					}
   852  					transitions = append(transitions, t)
   853  				}
   854  				rule["noncurrent_version_transition"] = schema.NewSet(transitionHash, transitions)
   855  			}
   856  
   857  			rules = append(rules, rule)
   858  		}
   859  
   860  		if err := d.Set("lifecycle_rule", rules); err != nil {
   861  			return err
   862  		}
   863  	}
   864  
   865  	// Read the bucket replication configuration
   866  	replication, err := s3conn.GetBucketReplication(&s3.GetBucketReplicationInput{
   867  		Bucket: aws.String(d.Id()),
   868  	})
   869  	if err != nil {
   870  		if awsError, ok := err.(awserr.RequestFailure); ok && awsError.StatusCode() != 404 {
   871  			return err
   872  		}
   873  	}
   874  
   875  	log.Printf("[DEBUG] S3 Bucket: %s, read replication configuration: %v", d.Id(), replication)
   876  	if r := replication.ReplicationConfiguration; r != nil {
   877  		if err := d.Set("replication_configuration", flattenAwsS3BucketReplicationConfiguration(replication.ReplicationConfiguration)); err != nil {
   878  			log.Printf("[DEBUG] Error setting replication configuration: %s", err)
   879  			return err
   880  		}
   881  	}
   882  
   883  	// Add the region as an attribute
   884  	location, err := s3conn.GetBucketLocation(
   885  		&s3.GetBucketLocationInput{
   886  			Bucket: aws.String(d.Id()),
   887  		},
   888  	)
   889  	if err != nil {
   890  		return err
   891  	}
   892  	var region string
   893  	if location.LocationConstraint != nil {
   894  		region = *location.LocationConstraint
   895  	}
   896  	region = normalizeRegion(region)
   897  	if err := d.Set("region", region); err != nil {
   898  		return err
   899  	}
   900  
   901  	// Add the hosted zone ID for this bucket's region as an attribute
   902  	hostedZoneID := HostedZoneIDForRegion(region)
   903  	if err := d.Set("hosted_zone_id", hostedZoneID); err != nil {
   904  		return err
   905  	}
   906  
   907  	// Add website_endpoint as an attribute
   908  	websiteEndpoint, err := websiteEndpoint(s3conn, d)
   909  	if err != nil {
   910  		return err
   911  	}
   912  	if websiteEndpoint != nil {
   913  		if err := d.Set("website_endpoint", websiteEndpoint.Endpoint); err != nil {
   914  			return err
   915  		}
   916  		if err := d.Set("website_domain", websiteEndpoint.Domain); err != nil {
   917  			return err
   918  		}
   919  	}
   920  
   921  	tagSet, err := getTagSetS3(s3conn, d.Id())
   922  	if err != nil {
   923  		return err
   924  	}
   925  
   926  	if err := d.Set("tags", tagsToMapS3(tagSet)); err != nil {
   927  		return err
   928  	}
   929  
   930  	d.Set("arn", fmt.Sprintf("arn:%s:s3:::%s", meta.(*AWSClient).partition, d.Id()))
   931  
   932  	return nil
   933  }
   934  
   935  func resourceAwsS3BucketDelete(d *schema.ResourceData, meta interface{}) error {
   936  	s3conn := meta.(*AWSClient).s3conn
   937  
   938  	log.Printf("[DEBUG] S3 Delete Bucket: %s", d.Id())
   939  	_, err := s3conn.DeleteBucket(&s3.DeleteBucketInput{
   940  		Bucket: aws.String(d.Id()),
   941  	})
   942  	if err != nil {
   943  		ec2err, ok := err.(awserr.Error)
   944  		if ok && ec2err.Code() == "BucketNotEmpty" {
   945  			if d.Get("force_destroy").(bool) {
   946  				// bucket may have things delete them
   947  				log.Printf("[DEBUG] S3 Bucket attempting to forceDestroy %+v", err)
   948  
   949  				bucket := d.Get("bucket").(string)
   950  				resp, err := s3conn.ListObjectVersions(
   951  					&s3.ListObjectVersionsInput{
   952  						Bucket: aws.String(bucket),
   953  					},
   954  				)
   955  
   956  				if err != nil {
   957  					return fmt.Errorf("Error S3 Bucket list Object Versions err: %s", err)
   958  				}
   959  
   960  				objectsToDelete := make([]*s3.ObjectIdentifier, 0)
   961  
   962  				if len(resp.DeleteMarkers) != 0 {
   963  
   964  					for _, v := range resp.DeleteMarkers {
   965  						objectsToDelete = append(objectsToDelete, &s3.ObjectIdentifier{
   966  							Key:       v.Key,
   967  							VersionId: v.VersionId,
   968  						})
   969  					}
   970  				}
   971  
   972  				if len(resp.Versions) != 0 {
   973  					for _, v := range resp.Versions {
   974  						objectsToDelete = append(objectsToDelete, &s3.ObjectIdentifier{
   975  							Key:       v.Key,
   976  							VersionId: v.VersionId,
   977  						})
   978  					}
   979  				}
   980  
   981  				params := &s3.DeleteObjectsInput{
   982  					Bucket: aws.String(bucket),
   983  					Delete: &s3.Delete{
   984  						Objects: objectsToDelete,
   985  					},
   986  				}
   987  
   988  				_, err = s3conn.DeleteObjects(params)
   989  
   990  				if err != nil {
   991  					return fmt.Errorf("Error S3 Bucket force_destroy error deleting: %s", err)
   992  				}
   993  
   994  				// this line recurses until all objects are deleted or an error is returned
   995  				return resourceAwsS3BucketDelete(d, meta)
   996  			}
   997  		}
   998  		return fmt.Errorf("Error deleting S3 Bucket: %s %q", err, d.Get("bucket").(string))
   999  	}
  1000  	return nil
  1001  }
  1002  
  1003  func resourceAwsS3BucketPolicyUpdate(s3conn *s3.S3, d *schema.ResourceData) error {
  1004  	bucket := d.Get("bucket").(string)
  1005  	policy := d.Get("policy").(string)
  1006  
  1007  	if policy != "" {
  1008  		log.Printf("[DEBUG] S3 bucket: %s, put policy: %s", bucket, policy)
  1009  
  1010  		params := &s3.PutBucketPolicyInput{
  1011  			Bucket: aws.String(bucket),
  1012  			Policy: aws.String(policy),
  1013  		}
  1014  
  1015  		err := resource.Retry(1*time.Minute, func() *resource.RetryError {
  1016  			if _, err := s3conn.PutBucketPolicy(params); err != nil {
  1017  				if awserr, ok := err.(awserr.Error); ok {
  1018  					if awserr.Code() == "MalformedPolicy" {
  1019  						return resource.RetryableError(awserr)
  1020  					}
  1021  				}
  1022  				return resource.NonRetryableError(err)
  1023  			}
  1024  			return nil
  1025  		})
  1026  
  1027  		if err != nil {
  1028  			return fmt.Errorf("Error putting S3 policy: %s", err)
  1029  		}
  1030  	} else {
  1031  		log.Printf("[DEBUG] S3 bucket: %s, delete policy: %s", bucket, policy)
  1032  		_, err := s3conn.DeleteBucketPolicy(&s3.DeleteBucketPolicyInput{
  1033  			Bucket: aws.String(bucket),
  1034  		})
  1035  
  1036  		if err != nil {
  1037  			return fmt.Errorf("Error deleting S3 policy: %s", err)
  1038  		}
  1039  	}
  1040  
  1041  	return nil
  1042  }
  1043  
  1044  func resourceAwsS3BucketCorsUpdate(s3conn *s3.S3, d *schema.ResourceData) error {
  1045  	bucket := d.Get("bucket").(string)
  1046  	rawCors := d.Get("cors_rule").([]interface{})
  1047  
  1048  	if len(rawCors) == 0 {
  1049  		// Delete CORS
  1050  		log.Printf("[DEBUG] S3 bucket: %s, delete CORS", bucket)
  1051  		_, err := s3conn.DeleteBucketCors(&s3.DeleteBucketCorsInput{
  1052  			Bucket: aws.String(bucket),
  1053  		})
  1054  		if err != nil {
  1055  			return fmt.Errorf("Error deleting S3 CORS: %s", err)
  1056  		}
  1057  	} else {
  1058  		// Put CORS
  1059  		rules := make([]*s3.CORSRule, 0, len(rawCors))
  1060  		for _, cors := range rawCors {
  1061  			corsMap := cors.(map[string]interface{})
  1062  			r := &s3.CORSRule{}
  1063  			for k, v := range corsMap {
  1064  				log.Printf("[DEBUG] S3 bucket: %s, put CORS: %#v, %#v", bucket, k, v)
  1065  				if k == "max_age_seconds" {
  1066  					r.MaxAgeSeconds = aws.Int64(int64(v.(int)))
  1067  				} else {
  1068  					vMap := make([]*string, len(v.([]interface{})))
  1069  					for i, vv := range v.([]interface{}) {
  1070  						str := vv.(string)
  1071  						vMap[i] = aws.String(str)
  1072  					}
  1073  					switch k {
  1074  					case "allowed_headers":
  1075  						r.AllowedHeaders = vMap
  1076  					case "allowed_methods":
  1077  						r.AllowedMethods = vMap
  1078  					case "allowed_origins":
  1079  						r.AllowedOrigins = vMap
  1080  					case "expose_headers":
  1081  						r.ExposeHeaders = vMap
  1082  					}
  1083  				}
  1084  			}
  1085  			rules = append(rules, r)
  1086  		}
  1087  		corsInput := &s3.PutBucketCorsInput{
  1088  			Bucket: aws.String(bucket),
  1089  			CORSConfiguration: &s3.CORSConfiguration{
  1090  				CORSRules: rules,
  1091  			},
  1092  		}
  1093  		log.Printf("[DEBUG] S3 bucket: %s, put CORS: %#v", bucket, corsInput)
  1094  		_, err := s3conn.PutBucketCors(corsInput)
  1095  		if err != nil {
  1096  			return fmt.Errorf("Error putting S3 CORS: %s", err)
  1097  		}
  1098  	}
  1099  
  1100  	return nil
  1101  }
  1102  
  1103  func resourceAwsS3BucketWebsiteUpdate(s3conn *s3.S3, d *schema.ResourceData) error {
  1104  	ws := d.Get("website").([]interface{})
  1105  
  1106  	if len(ws) == 1 {
  1107  		var w map[string]interface{}
  1108  		if ws[0] != nil {
  1109  			w = ws[0].(map[string]interface{})
  1110  		} else {
  1111  			w = make(map[string]interface{})
  1112  		}
  1113  		return resourceAwsS3BucketWebsitePut(s3conn, d, w)
  1114  	} else if len(ws) == 0 {
  1115  		return resourceAwsS3BucketWebsiteDelete(s3conn, d)
  1116  	} else {
  1117  		return fmt.Errorf("Cannot specify more than one website.")
  1118  	}
  1119  }
  1120  
  1121  func resourceAwsS3BucketWebsitePut(s3conn *s3.S3, d *schema.ResourceData, website map[string]interface{}) error {
  1122  	bucket := d.Get("bucket").(string)
  1123  
  1124  	var indexDocument, errorDocument, redirectAllRequestsTo, routingRules string
  1125  	if v, ok := website["index_document"]; ok {
  1126  		indexDocument = v.(string)
  1127  	}
  1128  	if v, ok := website["error_document"]; ok {
  1129  		errorDocument = v.(string)
  1130  	}
  1131  	if v, ok := website["redirect_all_requests_to"]; ok {
  1132  		redirectAllRequestsTo = v.(string)
  1133  	}
  1134  	if v, ok := website["routing_rules"]; ok {
  1135  		routingRules = v.(string)
  1136  	}
  1137  
  1138  	if indexDocument == "" && redirectAllRequestsTo == "" {
  1139  		return fmt.Errorf("Must specify either index_document or redirect_all_requests_to.")
  1140  	}
  1141  
  1142  	websiteConfiguration := &s3.WebsiteConfiguration{}
  1143  
  1144  	if indexDocument != "" {
  1145  		websiteConfiguration.IndexDocument = &s3.IndexDocument{Suffix: aws.String(indexDocument)}
  1146  	}
  1147  
  1148  	if errorDocument != "" {
  1149  		websiteConfiguration.ErrorDocument = &s3.ErrorDocument{Key: aws.String(errorDocument)}
  1150  	}
  1151  
  1152  	if redirectAllRequestsTo != "" {
  1153  		redirect, err := url.Parse(redirectAllRequestsTo)
  1154  		if err == nil && redirect.Scheme != "" {
  1155  			var redirectHostBuf bytes.Buffer
  1156  			redirectHostBuf.WriteString(redirect.Host)
  1157  			if redirect.Path != "" {
  1158  				redirectHostBuf.WriteString(redirect.Path)
  1159  			}
  1160  			websiteConfiguration.RedirectAllRequestsTo = &s3.RedirectAllRequestsTo{HostName: aws.String(redirectHostBuf.String()), Protocol: aws.String(redirect.Scheme)}
  1161  		} else {
  1162  			websiteConfiguration.RedirectAllRequestsTo = &s3.RedirectAllRequestsTo{HostName: aws.String(redirectAllRequestsTo)}
  1163  		}
  1164  	}
  1165  
  1166  	if routingRules != "" {
  1167  		var unmarshaledRules []*s3.RoutingRule
  1168  		if err := json.Unmarshal([]byte(routingRules), &unmarshaledRules); err != nil {
  1169  			return err
  1170  		}
  1171  		websiteConfiguration.RoutingRules = unmarshaledRules
  1172  	}
  1173  
  1174  	putInput := &s3.PutBucketWebsiteInput{
  1175  		Bucket:               aws.String(bucket),
  1176  		WebsiteConfiguration: websiteConfiguration,
  1177  	}
  1178  
  1179  	log.Printf("[DEBUG] S3 put bucket website: %#v", putInput)
  1180  
  1181  	_, err := s3conn.PutBucketWebsite(putInput)
  1182  	if err != nil {
  1183  		return fmt.Errorf("Error putting S3 website: %s", err)
  1184  	}
  1185  
  1186  	return nil
  1187  }
  1188  
  1189  func resourceAwsS3BucketWebsiteDelete(s3conn *s3.S3, d *schema.ResourceData) error {
  1190  	bucket := d.Get("bucket").(string)
  1191  	deleteInput := &s3.DeleteBucketWebsiteInput{Bucket: aws.String(bucket)}
  1192  
  1193  	log.Printf("[DEBUG] S3 delete bucket website: %#v", deleteInput)
  1194  
  1195  	_, err := s3conn.DeleteBucketWebsite(deleteInput)
  1196  	if err != nil {
  1197  		return fmt.Errorf("Error deleting S3 website: %s", err)
  1198  	}
  1199  
  1200  	d.Set("website_endpoint", "")
  1201  	d.Set("website_domain", "")
  1202  
  1203  	return nil
  1204  }
  1205  
  1206  func websiteEndpoint(s3conn *s3.S3, d *schema.ResourceData) (*S3Website, error) {
  1207  	// If the bucket doesn't have a website configuration, return an empty
  1208  	// endpoint
  1209  	if _, ok := d.GetOk("website"); !ok {
  1210  		return nil, nil
  1211  	}
  1212  
  1213  	bucket := d.Get("bucket").(string)
  1214  
  1215  	// Lookup the region for this bucket
  1216  	location, err := s3conn.GetBucketLocation(
  1217  		&s3.GetBucketLocationInput{
  1218  			Bucket: aws.String(bucket),
  1219  		},
  1220  	)
  1221  	if err != nil {
  1222  		return nil, err
  1223  	}
  1224  	var region string
  1225  	if location.LocationConstraint != nil {
  1226  		region = *location.LocationConstraint
  1227  	}
  1228  
  1229  	return WebsiteEndpoint(bucket, region), nil
  1230  }
  1231  
  1232  func bucketDomainName(bucket string) string {
  1233  	return fmt.Sprintf("%s.s3.amazonaws.com", bucket)
  1234  }
  1235  
  1236  func WebsiteEndpoint(bucket string, region string) *S3Website {
  1237  	domain := WebsiteDomainUrl(region)
  1238  	return &S3Website{Endpoint: fmt.Sprintf("%s.%s", bucket, domain), Domain: domain}
  1239  }
  1240  
  1241  func WebsiteDomainUrl(region string) string {
  1242  	region = normalizeRegion(region)
  1243  
  1244  	// New regions uses different syntax for website endpoints
  1245  	// http://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteEndpoints.html
  1246  	if isOldRegion(region) {
  1247  		return fmt.Sprintf("s3-website-%s.amazonaws.com", region)
  1248  	}
  1249  	return fmt.Sprintf("s3-website.%s.amazonaws.com", region)
  1250  }
  1251  
  1252  func isOldRegion(region string) bool {
  1253  	oldRegions := []string{
  1254  		"ap-northeast-1",
  1255  		"ap-southeast-1",
  1256  		"ap-southeast-2",
  1257  		"eu-west-1",
  1258  		"sa-east-1",
  1259  		"us-east-1",
  1260  		"us-gov-west-1",
  1261  		"us-west-1",
  1262  		"us-west-2",
  1263  	}
  1264  	for _, r := range oldRegions {
  1265  		if region == r {
  1266  			return true
  1267  		}
  1268  	}
  1269  	return false
  1270  }
  1271  
  1272  func resourceAwsS3BucketAclUpdate(s3conn *s3.S3, d *schema.ResourceData) error {
  1273  	acl := d.Get("acl").(string)
  1274  	bucket := d.Get("bucket").(string)
  1275  
  1276  	i := &s3.PutBucketAclInput{
  1277  		Bucket: aws.String(bucket),
  1278  		ACL:    aws.String(acl),
  1279  	}
  1280  	log.Printf("[DEBUG] S3 put bucket ACL: %#v", i)
  1281  
  1282  	_, err := s3conn.PutBucketAcl(i)
  1283  	if err != nil {
  1284  		return fmt.Errorf("Error putting S3 ACL: %s", err)
  1285  	}
  1286  
  1287  	return nil
  1288  }
  1289  
  1290  func resourceAwsS3BucketVersioningUpdate(s3conn *s3.S3, d *schema.ResourceData) error {
  1291  	v := d.Get("versioning").([]interface{})
  1292  	bucket := d.Get("bucket").(string)
  1293  	vc := &s3.VersioningConfiguration{}
  1294  
  1295  	if len(v) > 0 {
  1296  		c := v[0].(map[string]interface{})
  1297  
  1298  		if c["enabled"].(bool) {
  1299  			vc.Status = aws.String(s3.BucketVersioningStatusEnabled)
  1300  		} else {
  1301  			vc.Status = aws.String(s3.BucketVersioningStatusSuspended)
  1302  		}
  1303  
  1304  		if c["mfa_delete"].(bool) {
  1305  			vc.MFADelete = aws.String(s3.MFADeleteEnabled)
  1306  		} else {
  1307  			vc.MFADelete = aws.String(s3.MFADeleteDisabled)
  1308  		}
  1309  
  1310  	} else {
  1311  		vc.Status = aws.String(s3.BucketVersioningStatusSuspended)
  1312  	}
  1313  
  1314  	i := &s3.PutBucketVersioningInput{
  1315  		Bucket:                  aws.String(bucket),
  1316  		VersioningConfiguration: vc,
  1317  	}
  1318  	log.Printf("[DEBUG] S3 put bucket versioning: %#v", i)
  1319  
  1320  	_, err := s3conn.PutBucketVersioning(i)
  1321  	if err != nil {
  1322  		return fmt.Errorf("Error putting S3 versioning: %s", err)
  1323  	}
  1324  
  1325  	return nil
  1326  }
  1327  
  1328  func resourceAwsS3BucketLoggingUpdate(s3conn *s3.S3, d *schema.ResourceData) error {
  1329  	logging := d.Get("logging").(*schema.Set).List()
  1330  	bucket := d.Get("bucket").(string)
  1331  	loggingStatus := &s3.BucketLoggingStatus{}
  1332  
  1333  	if len(logging) > 0 {
  1334  		c := logging[0].(map[string]interface{})
  1335  
  1336  		loggingEnabled := &s3.LoggingEnabled{}
  1337  		if val, ok := c["target_bucket"]; ok {
  1338  			loggingEnabled.TargetBucket = aws.String(val.(string))
  1339  		}
  1340  		if val, ok := c["target_prefix"]; ok {
  1341  			loggingEnabled.TargetPrefix = aws.String(val.(string))
  1342  		}
  1343  
  1344  		loggingStatus.LoggingEnabled = loggingEnabled
  1345  	}
  1346  
  1347  	i := &s3.PutBucketLoggingInput{
  1348  		Bucket:              aws.String(bucket),
  1349  		BucketLoggingStatus: loggingStatus,
  1350  	}
  1351  	log.Printf("[DEBUG] S3 put bucket logging: %#v", i)
  1352  
  1353  	_, err := s3conn.PutBucketLogging(i)
  1354  	if err != nil {
  1355  		return fmt.Errorf("Error putting S3 logging: %s", err)
  1356  	}
  1357  
  1358  	return nil
  1359  }
  1360  
  1361  func resourceAwsS3BucketAccelerationUpdate(s3conn *s3.S3, d *schema.ResourceData) error {
  1362  	bucket := d.Get("bucket").(string)
  1363  	enableAcceleration := d.Get("acceleration_status").(string)
  1364  
  1365  	i := &s3.PutBucketAccelerateConfigurationInput{
  1366  		Bucket: aws.String(bucket),
  1367  		AccelerateConfiguration: &s3.AccelerateConfiguration{
  1368  			Status: aws.String(enableAcceleration),
  1369  		},
  1370  	}
  1371  	log.Printf("[DEBUG] S3 put bucket acceleration: %#v", i)
  1372  
  1373  	_, err := s3conn.PutBucketAccelerateConfiguration(i)
  1374  	if err != nil {
  1375  		return fmt.Errorf("Error putting S3 acceleration: %s", err)
  1376  	}
  1377  
  1378  	return nil
  1379  }
  1380  
  1381  func resourceAwsS3BucketRequestPayerUpdate(s3conn *s3.S3, d *schema.ResourceData) error {
  1382  	bucket := d.Get("bucket").(string)
  1383  	payer := d.Get("request_payer").(string)
  1384  
  1385  	i := &s3.PutBucketRequestPaymentInput{
  1386  		Bucket: aws.String(bucket),
  1387  		RequestPaymentConfiguration: &s3.RequestPaymentConfiguration{
  1388  			Payer: aws.String(payer),
  1389  		},
  1390  	}
  1391  	log.Printf("[DEBUG] S3 put bucket request payer: %#v", i)
  1392  
  1393  	_, err := s3conn.PutBucketRequestPayment(i)
  1394  	if err != nil {
  1395  		return fmt.Errorf("Error putting S3 request payer: %s", err)
  1396  	}
  1397  
  1398  	return nil
  1399  }
  1400  
  1401  func resourceAwsS3BucketReplicationConfigurationUpdate(s3conn *s3.S3, d *schema.ResourceData) error {
  1402  	bucket := d.Get("bucket").(string)
  1403  	replicationConfiguration := d.Get("replication_configuration").([]interface{})
  1404  
  1405  	if len(replicationConfiguration) == 0 {
  1406  		i := &s3.DeleteBucketReplicationInput{
  1407  			Bucket: aws.String(bucket),
  1408  		}
  1409  
  1410  		err := resource.Retry(1*time.Minute, func() *resource.RetryError {
  1411  			if _, err := s3conn.DeleteBucketReplication(i); err != nil {
  1412  				return resource.NonRetryableError(err)
  1413  			}
  1414  			return nil
  1415  		})
  1416  		if err != nil {
  1417  			return fmt.Errorf("Error removing S3 bucket replication: %s", err)
  1418  		}
  1419  		return nil
  1420  	}
  1421  
  1422  	hasVersioning := false
  1423  	// Validate that bucket versioning is enabled
  1424  	if versioning, ok := d.GetOk("versioning"); ok {
  1425  		v := versioning.([]interface{})
  1426  
  1427  		if v[0].(map[string]interface{})["enabled"].(bool) {
  1428  			hasVersioning = true
  1429  		}
  1430  	}
  1431  
  1432  	if !hasVersioning {
  1433  		return fmt.Errorf("versioning must be enabled to allow S3 bucket replication")
  1434  	}
  1435  
  1436  	c := replicationConfiguration[0].(map[string]interface{})
  1437  
  1438  	rc := &s3.ReplicationConfiguration{}
  1439  	if val, ok := c["role"]; ok {
  1440  		rc.Role = aws.String(val.(string))
  1441  	}
  1442  
  1443  	rcRules := c["rules"].(*schema.Set).List()
  1444  	rules := []*s3.ReplicationRule{}
  1445  	for _, v := range rcRules {
  1446  		rr := v.(map[string]interface{})
  1447  		rcRule := &s3.ReplicationRule{
  1448  			Prefix: aws.String(rr["prefix"].(string)),
  1449  			Status: aws.String(rr["status"].(string)),
  1450  		}
  1451  
  1452  		if rrid, ok := rr["id"]; ok {
  1453  			rcRule.ID = aws.String(rrid.(string))
  1454  		}
  1455  
  1456  		ruleDestination := &s3.Destination{}
  1457  		if destination, ok := rr["destination"]; ok {
  1458  			dest := destination.(*schema.Set).List()
  1459  
  1460  			bd := dest[0].(map[string]interface{})
  1461  			ruleDestination.Bucket = aws.String(bd["bucket"].(string))
  1462  
  1463  			if storageClass, ok := bd["storage_class"]; ok && storageClass != "" {
  1464  				ruleDestination.StorageClass = aws.String(storageClass.(string))
  1465  			}
  1466  		}
  1467  		rcRule.Destination = ruleDestination
  1468  		rules = append(rules, rcRule)
  1469  	}
  1470  
  1471  	rc.Rules = rules
  1472  	i := &s3.PutBucketReplicationInput{
  1473  		Bucket: aws.String(bucket),
  1474  		ReplicationConfiguration: rc,
  1475  	}
  1476  	log.Printf("[DEBUG] S3 put bucket replication configuration: %#v", i)
  1477  
  1478  	_, err := s3conn.PutBucketReplication(i)
  1479  	if err != nil {
  1480  		return fmt.Errorf("Error putting S3 replication configuration: %s", err)
  1481  	}
  1482  
  1483  	return nil
  1484  }
  1485  
  1486  func resourceAwsS3BucketLifecycleUpdate(s3conn *s3.S3, d *schema.ResourceData) error {
  1487  	bucket := d.Get("bucket").(string)
  1488  
  1489  	lifecycleRules := d.Get("lifecycle_rule").([]interface{})
  1490  
  1491  	if len(lifecycleRules) == 0 {
  1492  		i := &s3.DeleteBucketLifecycleInput{
  1493  			Bucket: aws.String(bucket),
  1494  		}
  1495  
  1496  		err := resource.Retry(1*time.Minute, func() *resource.RetryError {
  1497  			if _, err := s3conn.DeleteBucketLifecycle(i); err != nil {
  1498  				return resource.NonRetryableError(err)
  1499  			}
  1500  			return nil
  1501  		})
  1502  		if err != nil {
  1503  			return fmt.Errorf("Error removing S3 lifecycle: %s", err)
  1504  		}
  1505  		return nil
  1506  	}
  1507  
  1508  	rules := make([]*s3.LifecycleRule, 0, len(lifecycleRules))
  1509  
  1510  	for i, lifecycleRule := range lifecycleRules {
  1511  		r := lifecycleRule.(map[string]interface{})
  1512  
  1513  		rule := &s3.LifecycleRule{
  1514  			Prefix: aws.String(r["prefix"].(string)),
  1515  		}
  1516  
  1517  		// ID
  1518  		if val, ok := r["id"].(string); ok && val != "" {
  1519  			rule.ID = aws.String(val)
  1520  		} else {
  1521  			rule.ID = aws.String(resource.PrefixedUniqueId("tf-s3-lifecycle-"))
  1522  		}
  1523  
  1524  		// Enabled
  1525  		if val, ok := r["enabled"].(bool); ok && val {
  1526  			rule.Status = aws.String(s3.ExpirationStatusEnabled)
  1527  		} else {
  1528  			rule.Status = aws.String(s3.ExpirationStatusDisabled)
  1529  		}
  1530  
  1531  		// AbortIncompleteMultipartUpload
  1532  		if val, ok := r["abort_incomplete_multipart_upload_days"].(int); ok && val > 0 {
  1533  			rule.AbortIncompleteMultipartUpload = &s3.AbortIncompleteMultipartUpload{
  1534  				DaysAfterInitiation: aws.Int64(int64(val)),
  1535  			}
  1536  		}
  1537  
  1538  		// Expiration
  1539  		expiration := d.Get(fmt.Sprintf("lifecycle_rule.%d.expiration", i)).(*schema.Set).List()
  1540  		if len(expiration) > 0 {
  1541  			e := expiration[0].(map[string]interface{})
  1542  			i := &s3.LifecycleExpiration{}
  1543  
  1544  			if val, ok := e["date"].(string); ok && val != "" {
  1545  				t, err := time.Parse(time.RFC3339, fmt.Sprintf("%sT00:00:00Z", val))
  1546  				if err != nil {
  1547  					return fmt.Errorf("Error Parsing AWS S3 Bucket Lifecycle Expiration Date: %s", err.Error())
  1548  				}
  1549  				i.Date = aws.Time(t)
  1550  			} else if val, ok := e["days"].(int); ok && val > 0 {
  1551  				i.Days = aws.Int64(int64(val))
  1552  			} else if val, ok := e["expired_object_delete_marker"].(bool); ok {
  1553  				i.ExpiredObjectDeleteMarker = aws.Bool(val)
  1554  			}
  1555  			rule.Expiration = i
  1556  		}
  1557  
  1558  		// NoncurrentVersionExpiration
  1559  		nc_expiration := d.Get(fmt.Sprintf("lifecycle_rule.%d.noncurrent_version_expiration", i)).(*schema.Set).List()
  1560  		if len(nc_expiration) > 0 {
  1561  			e := nc_expiration[0].(map[string]interface{})
  1562  
  1563  			if val, ok := e["days"].(int); ok && val > 0 {
  1564  				rule.NoncurrentVersionExpiration = &s3.NoncurrentVersionExpiration{
  1565  					NoncurrentDays: aws.Int64(int64(val)),
  1566  				}
  1567  			}
  1568  		}
  1569  
  1570  		// Transitions
  1571  		transitions := d.Get(fmt.Sprintf("lifecycle_rule.%d.transition", i)).(*schema.Set).List()
  1572  		if len(transitions) > 0 {
  1573  			rule.Transitions = make([]*s3.Transition, 0, len(transitions))
  1574  			for _, transition := range transitions {
  1575  				transition := transition.(map[string]interface{})
  1576  				i := &s3.Transition{}
  1577  				if val, ok := transition["date"].(string); ok && val != "" {
  1578  					t, err := time.Parse(time.RFC3339, fmt.Sprintf("%sT00:00:00Z", val))
  1579  					if err != nil {
  1580  						return fmt.Errorf("Error Parsing AWS S3 Bucket Lifecycle Expiration Date: %s", err.Error())
  1581  					}
  1582  					i.Date = aws.Time(t)
  1583  				} else if val, ok := transition["days"].(int); ok && val > 0 {
  1584  					i.Days = aws.Int64(int64(val))
  1585  				}
  1586  				if val, ok := transition["storage_class"].(string); ok && val != "" {
  1587  					i.StorageClass = aws.String(val)
  1588  				}
  1589  
  1590  				rule.Transitions = append(rule.Transitions, i)
  1591  			}
  1592  		}
  1593  		// NoncurrentVersionTransitions
  1594  		nc_transitions := d.Get(fmt.Sprintf("lifecycle_rule.%d.noncurrent_version_transition", i)).(*schema.Set).List()
  1595  		if len(nc_transitions) > 0 {
  1596  			rule.NoncurrentVersionTransitions = make([]*s3.NoncurrentVersionTransition, 0, len(nc_transitions))
  1597  			for _, transition := range nc_transitions {
  1598  				transition := transition.(map[string]interface{})
  1599  				i := &s3.NoncurrentVersionTransition{}
  1600  				if val, ok := transition["days"].(int); ok && val > 0 {
  1601  					i.NoncurrentDays = aws.Int64(int64(val))
  1602  				}
  1603  				if val, ok := transition["storage_class"].(string); ok && val != "" {
  1604  					i.StorageClass = aws.String(val)
  1605  				}
  1606  
  1607  				rule.NoncurrentVersionTransitions = append(rule.NoncurrentVersionTransitions, i)
  1608  			}
  1609  		}
  1610  
  1611  		rules = append(rules, rule)
  1612  	}
  1613  
  1614  	i := &s3.PutBucketLifecycleConfigurationInput{
  1615  		Bucket: aws.String(bucket),
  1616  		LifecycleConfiguration: &s3.BucketLifecycleConfiguration{
  1617  			Rules: rules,
  1618  		},
  1619  	}
  1620  
  1621  	err := resource.Retry(1*time.Minute, func() *resource.RetryError {
  1622  		if _, err := s3conn.PutBucketLifecycleConfiguration(i); err != nil {
  1623  			return resource.NonRetryableError(err)
  1624  		}
  1625  		return nil
  1626  	})
  1627  	if err != nil {
  1628  		return fmt.Errorf("Error putting S3 lifecycle: %s", err)
  1629  	}
  1630  
  1631  	return nil
  1632  }
  1633  
  1634  func flattenAwsS3BucketReplicationConfiguration(r *s3.ReplicationConfiguration) []map[string]interface{} {
  1635  	replication_configuration := make([]map[string]interface{}, 0, 1)
  1636  	m := make(map[string]interface{})
  1637  
  1638  	if r.Role != nil && *r.Role != "" {
  1639  		m["role"] = *r.Role
  1640  	}
  1641  
  1642  	rules := make([]interface{}, 0, len(r.Rules))
  1643  	for _, v := range r.Rules {
  1644  		t := make(map[string]interface{})
  1645  		if v.Destination != nil {
  1646  			rd := make(map[string]interface{})
  1647  			if v.Destination.Bucket != nil {
  1648  				rd["bucket"] = *v.Destination.Bucket
  1649  			}
  1650  			if v.Destination.StorageClass != nil {
  1651  				rd["storage_class"] = *v.Destination.StorageClass
  1652  			}
  1653  			t["destination"] = schema.NewSet(destinationHash, []interface{}{rd})
  1654  		}
  1655  
  1656  		if v.ID != nil {
  1657  			t["id"] = *v.ID
  1658  		}
  1659  		if v.Prefix != nil {
  1660  			t["prefix"] = *v.Prefix
  1661  		}
  1662  		if v.Status != nil {
  1663  			t["status"] = *v.Status
  1664  		}
  1665  		rules = append(rules, t)
  1666  	}
  1667  	m["rules"] = schema.NewSet(rulesHash, rules)
  1668  
  1669  	replication_configuration = append(replication_configuration, m)
  1670  
  1671  	return replication_configuration
  1672  }
  1673  
  1674  func normalizeRoutingRules(w []*s3.RoutingRule) (string, error) {
  1675  	withNulls, err := json.Marshal(w)
  1676  	if err != nil {
  1677  		return "", err
  1678  	}
  1679  
  1680  	var rules []map[string]interface{}
  1681  	if err := json.Unmarshal(withNulls, &rules); err != nil {
  1682  		return "", err
  1683  	}
  1684  
  1685  	var cleanRules []map[string]interface{}
  1686  	for _, rule := range rules {
  1687  		cleanRules = append(cleanRules, removeNil(rule))
  1688  	}
  1689  
  1690  	withoutNulls, err := json.Marshal(cleanRules)
  1691  	if err != nil {
  1692  		return "", err
  1693  	}
  1694  
  1695  	return string(withoutNulls), nil
  1696  }
  1697  
  1698  func removeNil(data map[string]interface{}) map[string]interface{} {
  1699  	withoutNil := make(map[string]interface{})
  1700  
  1701  	for k, v := range data {
  1702  		if v == nil {
  1703  			continue
  1704  		}
  1705  
  1706  		switch v.(type) {
  1707  		case map[string]interface{}:
  1708  			withoutNil[k] = removeNil(v.(map[string]interface{}))
  1709  		default:
  1710  			withoutNil[k] = v
  1711  		}
  1712  	}
  1713  
  1714  	return withoutNil
  1715  }
  1716  
  1717  // DEPRECATED. Please consider using `normalizeJsonString` function instead.
  1718  func normalizeJson(jsonString interface{}) string {
  1719  	if jsonString == nil || jsonString == "" {
  1720  		return ""
  1721  	}
  1722  	var j interface{}
  1723  	err := json.Unmarshal([]byte(jsonString.(string)), &j)
  1724  	if err != nil {
  1725  		return fmt.Sprintf("Error parsing JSON: %s", err)
  1726  	}
  1727  	b, _ := json.Marshal(j)
  1728  	return string(b[:])
  1729  }
  1730  
  1731  func normalizeRegion(region string) string {
  1732  	// Default to us-east-1 if the bucket doesn't have a region:
  1733  	// http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGETlocation.html
  1734  	if region == "" {
  1735  		region = "us-east-1"
  1736  	}
  1737  
  1738  	return region
  1739  }
  1740  
  1741  func validateS3BucketAccelerationStatus(v interface{}, k string) (ws []string, errors []error) {
  1742  	validTypes := map[string]struct{}{
  1743  		"Enabled":   struct{}{},
  1744  		"Suspended": struct{}{},
  1745  	}
  1746  
  1747  	if _, ok := validTypes[v.(string)]; !ok {
  1748  		errors = append(errors, fmt.Errorf("S3 Bucket Acceleration Status %q is invalid, must be %q or %q", v.(string), "Enabled", "Suspended"))
  1749  	}
  1750  	return
  1751  }
  1752  
  1753  func validateS3BucketRequestPayerType(v interface{}, k string) (ws []string, errors []error) {
  1754  	value := v.(string)
  1755  	if value != s3.PayerRequester && value != s3.PayerBucketOwner {
  1756  		errors = append(errors, fmt.Errorf(
  1757  			"%q contains an invalid Request Payer type %q. Valid types are either %q or %q",
  1758  			k, value, s3.PayerRequester, s3.PayerBucketOwner))
  1759  	}
  1760  	return
  1761  }
  1762  
  1763  // validateS3BucketName validates any S3 bucket name that is not inside the us-east-1 region.
  1764  // Buckets outside of this region have to be DNS-compliant. After the same restrictions are
  1765  // applied to buckets in the us-east-1 region, this function can be refactored as a SchemaValidateFunc
  1766  func validateS3BucketName(value string, region string) error {
  1767  	if region != "us-east-1" {
  1768  		if (len(value) < 3) || (len(value) > 63) {
  1769  			return fmt.Errorf("%q must contain from 3 to 63 characters", value)
  1770  		}
  1771  		if !regexp.MustCompile(`^[0-9a-z-.]+$`).MatchString(value) {
  1772  			return fmt.Errorf("only lowercase alphanumeric characters and hyphens allowed in %q", value)
  1773  		}
  1774  		if regexp.MustCompile(`^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$`).MatchString(value) {
  1775  			return fmt.Errorf("%q must not be formatted as an IP address", value)
  1776  		}
  1777  		if strings.HasPrefix(value, `.`) {
  1778  			return fmt.Errorf("%q cannot start with a period", value)
  1779  		}
  1780  		if strings.HasSuffix(value, `.`) {
  1781  			return fmt.Errorf("%q cannot end with a period", value)
  1782  		}
  1783  		if strings.Contains(value, `..`) {
  1784  			return fmt.Errorf("%q can be only one period between labels", value)
  1785  		}
  1786  	} else {
  1787  		if len(value) > 255 {
  1788  			return fmt.Errorf("%q must contain less than 256 characters", value)
  1789  		}
  1790  		if !regexp.MustCompile(`^[0-9a-zA-Z-._]+$`).MatchString(value) {
  1791  			return fmt.Errorf("only alphanumeric characters, hyphens, periods, and underscores allowed in %q", value)
  1792  		}
  1793  	}
  1794  	return nil
  1795  }
  1796  
  1797  func expirationHash(v interface{}) int {
  1798  	var buf bytes.Buffer
  1799  	m := v.(map[string]interface{})
  1800  	if v, ok := m["date"]; ok {
  1801  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
  1802  	}
  1803  	if v, ok := m["days"]; ok {
  1804  		buf.WriteString(fmt.Sprintf("%d-", v.(int)))
  1805  	}
  1806  	if v, ok := m["expired_object_delete_marker"]; ok {
  1807  		buf.WriteString(fmt.Sprintf("%t-", v.(bool)))
  1808  	}
  1809  	return hashcode.String(buf.String())
  1810  }
  1811  
  1812  func transitionHash(v interface{}) int {
  1813  	var buf bytes.Buffer
  1814  	m := v.(map[string]interface{})
  1815  	if v, ok := m["date"]; ok {
  1816  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
  1817  	}
  1818  	if v, ok := m["days"]; ok {
  1819  		buf.WriteString(fmt.Sprintf("%d-", v.(int)))
  1820  	}
  1821  	if v, ok := m["storage_class"]; ok {
  1822  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
  1823  	}
  1824  	return hashcode.String(buf.String())
  1825  }
  1826  
  1827  func rulesHash(v interface{}) int {
  1828  	var buf bytes.Buffer
  1829  	m := v.(map[string]interface{})
  1830  
  1831  	if v, ok := m["id"]; ok {
  1832  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
  1833  	}
  1834  	if v, ok := m["prefix"]; ok {
  1835  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
  1836  	}
  1837  	if v, ok := m["status"]; ok {
  1838  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
  1839  	}
  1840  	return hashcode.String(buf.String())
  1841  }
  1842  
  1843  func destinationHash(v interface{}) int {
  1844  	var buf bytes.Buffer
  1845  	m := v.(map[string]interface{})
  1846  
  1847  	if v, ok := m["bucket"]; ok {
  1848  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
  1849  	}
  1850  	if v, ok := m["storage_class"]; ok {
  1851  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
  1852  	}
  1853  	return hashcode.String(buf.String())
  1854  }
  1855  
  1856  type S3Website struct {
  1857  	Endpoint, Domain string
  1858  }