github.com/gabrielperezs/terraform@v0.7.0-rc2.0.20160715084931-f7da2612946f/builtin/providers/aws/resource_aws_cloudfront_distribution.go (about)

     1  package aws
     2  
     3  import (
     4  	"log"
     5  	"time"
     6  
     7  	"github.com/aws/aws-sdk-go/aws"
     8  	"github.com/aws/aws-sdk-go/service/cloudfront"
     9  	"github.com/hashicorp/terraform/helper/resource"
    10  	"github.com/hashicorp/terraform/helper/schema"
    11  )
    12  
    13  func resourceAwsCloudFrontDistribution() *schema.Resource {
    14  	return &schema.Resource{
    15  		Create: resourceAwsCloudFrontDistributionCreate,
    16  		Read:   resourceAwsCloudFrontDistributionRead,
    17  		Update: resourceAwsCloudFrontDistributionUpdate,
    18  		Delete: resourceAwsCloudFrontDistributionDelete,
    19  
    20  		Schema: map[string]*schema.Schema{
    21  			"aliases": &schema.Schema{
    22  				Type:     schema.TypeSet,
    23  				Optional: true,
    24  				Elem:     &schema.Schema{Type: schema.TypeString},
    25  				Set:      aliasesHash,
    26  			},
    27  			"cache_behavior": &schema.Schema{
    28  				Type:     schema.TypeSet,
    29  				Optional: true,
    30  				Set:      cacheBehaviorHash,
    31  				Elem: &schema.Resource{
    32  					Schema: map[string]*schema.Schema{
    33  						"allowed_methods": &schema.Schema{
    34  							Type:     schema.TypeList,
    35  							Required: true,
    36  							Elem:     &schema.Schema{Type: schema.TypeString},
    37  						},
    38  						"cached_methods": &schema.Schema{
    39  							Type:     schema.TypeList,
    40  							Required: true,
    41  							Elem:     &schema.Schema{Type: schema.TypeString},
    42  						},
    43  						"compress": &schema.Schema{
    44  							Type:     schema.TypeBool,
    45  							Optional: true,
    46  							Default:  false,
    47  						},
    48  						"default_ttl": &schema.Schema{
    49  							Type:     schema.TypeInt,
    50  							Required: true,
    51  						},
    52  						"forwarded_values": &schema.Schema{
    53  							Type:     schema.TypeSet,
    54  							Required: true,
    55  							Set:      forwardedValuesHash,
    56  							MaxItems: 1,
    57  							Elem: &schema.Resource{
    58  								Schema: map[string]*schema.Schema{
    59  									"cookies": &schema.Schema{
    60  										Type:     schema.TypeSet,
    61  										Required: true,
    62  										Set:      cookiePreferenceHash,
    63  										MaxItems: 1,
    64  										Elem: &schema.Resource{
    65  											Schema: map[string]*schema.Schema{
    66  												"forward": &schema.Schema{
    67  													Type:     schema.TypeString,
    68  													Required: true,
    69  												},
    70  												"whitelisted_names": &schema.Schema{
    71  													Type:     schema.TypeList,
    72  													Optional: true,
    73  													Elem:     &schema.Schema{Type: schema.TypeString},
    74  												},
    75  											},
    76  										},
    77  									},
    78  									"headers": &schema.Schema{
    79  										Type:     schema.TypeList,
    80  										Optional: true,
    81  										Elem:     &schema.Schema{Type: schema.TypeString},
    82  									},
    83  									"query_string": &schema.Schema{
    84  										Type:     schema.TypeBool,
    85  										Required: true,
    86  									},
    87  								},
    88  							},
    89  						},
    90  						"max_ttl": &schema.Schema{
    91  							Type:     schema.TypeInt,
    92  							Required: true,
    93  						},
    94  						"min_ttl": &schema.Schema{
    95  							Type:     schema.TypeInt,
    96  							Required: true,
    97  						},
    98  						"path_pattern": &schema.Schema{
    99  							Type:     schema.TypeString,
   100  							Required: true,
   101  						},
   102  						"smooth_streaming": &schema.Schema{
   103  							Type:     schema.TypeBool,
   104  							Optional: true,
   105  						},
   106  						"target_origin_id": &schema.Schema{
   107  							Type:     schema.TypeString,
   108  							Required: true,
   109  						},
   110  						"trusted_signers": &schema.Schema{
   111  							Type:     schema.TypeList,
   112  							Optional: true,
   113  							Elem:     &schema.Schema{Type: schema.TypeString},
   114  						},
   115  						"viewer_protocol_policy": &schema.Schema{
   116  							Type:     schema.TypeString,
   117  							Required: true,
   118  						},
   119  					},
   120  				},
   121  			},
   122  			"comment": &schema.Schema{
   123  				Type:     schema.TypeString,
   124  				Optional: true,
   125  			},
   126  			"custom_error_response": &schema.Schema{
   127  				Type:     schema.TypeSet,
   128  				Optional: true,
   129  				Set:      customErrorResponseHash,
   130  				Elem: &schema.Resource{
   131  					Schema: map[string]*schema.Schema{
   132  						"error_caching_min_ttl": &schema.Schema{
   133  							Type:     schema.TypeInt,
   134  							Optional: true,
   135  						},
   136  						"error_code": &schema.Schema{
   137  							Type:     schema.TypeInt,
   138  							Required: true,
   139  						},
   140  						"response_code": &schema.Schema{
   141  							Type:     schema.TypeInt,
   142  							Optional: true,
   143  						},
   144  						"response_page_path": &schema.Schema{
   145  							Type:     schema.TypeString,
   146  							Optional: true,
   147  						},
   148  					},
   149  				},
   150  			},
   151  			"default_cache_behavior": &schema.Schema{
   152  				Type:     schema.TypeSet,
   153  				Required: true,
   154  				Set:      defaultCacheBehaviorHash,
   155  				MaxItems: 1,
   156  				Elem: &schema.Resource{
   157  					Schema: map[string]*schema.Schema{
   158  						"allowed_methods": &schema.Schema{
   159  							Type:     schema.TypeList,
   160  							Required: true,
   161  							Elem:     &schema.Schema{Type: schema.TypeString},
   162  						},
   163  						"cached_methods": &schema.Schema{
   164  							Type:     schema.TypeList,
   165  							Required: true,
   166  							Elem:     &schema.Schema{Type: schema.TypeString},
   167  						},
   168  						"compress": &schema.Schema{
   169  							Type:     schema.TypeBool,
   170  							Optional: true,
   171  							Default:  false,
   172  						},
   173  						"default_ttl": &schema.Schema{
   174  							Type:     schema.TypeInt,
   175  							Required: true,
   176  						},
   177  						"forwarded_values": &schema.Schema{
   178  							Type:     schema.TypeSet,
   179  							Required: true,
   180  							Set:      forwardedValuesHash,
   181  							MaxItems: 1,
   182  							Elem: &schema.Resource{
   183  								Schema: map[string]*schema.Schema{
   184  									"cookies": &schema.Schema{
   185  										Type:     schema.TypeSet,
   186  										Optional: true,
   187  										Set:      cookiePreferenceHash,
   188  										MaxItems: 1,
   189  										Elem: &schema.Resource{
   190  											Schema: map[string]*schema.Schema{
   191  												"forward": &schema.Schema{
   192  													Type:     schema.TypeString,
   193  													Required: true,
   194  												},
   195  												"whitelisted_names": &schema.Schema{
   196  													Type:     schema.TypeList,
   197  													Optional: true,
   198  													Elem:     &schema.Schema{Type: schema.TypeString},
   199  												},
   200  											},
   201  										},
   202  									},
   203  									"headers": &schema.Schema{
   204  										Type:     schema.TypeList,
   205  										Optional: true,
   206  										Elem:     &schema.Schema{Type: schema.TypeString},
   207  									},
   208  									"query_string": &schema.Schema{
   209  										Type:     schema.TypeBool,
   210  										Required: true,
   211  									},
   212  								},
   213  							},
   214  						},
   215  						"max_ttl": &schema.Schema{
   216  							Type:     schema.TypeInt,
   217  							Required: true,
   218  						},
   219  						"min_ttl": &schema.Schema{
   220  							Type:     schema.TypeInt,
   221  							Required: true,
   222  						},
   223  						"smooth_streaming": &schema.Schema{
   224  							Type:     schema.TypeBool,
   225  							Optional: true,
   226  						},
   227  						"target_origin_id": &schema.Schema{
   228  							Type:     schema.TypeString,
   229  							Required: true,
   230  						},
   231  						"trusted_signers": &schema.Schema{
   232  							Type:     schema.TypeList,
   233  							Optional: true,
   234  							Elem:     &schema.Schema{Type: schema.TypeString},
   235  						},
   236  						"viewer_protocol_policy": &schema.Schema{
   237  							Type:     schema.TypeString,
   238  							Required: true,
   239  						},
   240  					},
   241  				},
   242  			},
   243  			"default_root_object": &schema.Schema{
   244  				Type:     schema.TypeString,
   245  				Optional: true,
   246  			},
   247  			"enabled": &schema.Schema{
   248  				Type:     schema.TypeBool,
   249  				Required: true,
   250  			},
   251  			"logging_config": &schema.Schema{
   252  				Type:     schema.TypeSet,
   253  				Optional: true,
   254  				Set:      loggingConfigHash,
   255  				MaxItems: 1,
   256  				Elem: &schema.Resource{
   257  					Schema: map[string]*schema.Schema{
   258  						"bucket": &schema.Schema{
   259  							Type:     schema.TypeString,
   260  							Required: true,
   261  						},
   262  						"include_cookies": &schema.Schema{
   263  							Type:     schema.TypeBool,
   264  							Optional: true,
   265  							Default:  false,
   266  						},
   267  						"prefix": &schema.Schema{
   268  							Type:     schema.TypeString,
   269  							Optional: true,
   270  							Default:  "",
   271  						},
   272  					},
   273  				},
   274  			},
   275  			"origin": &schema.Schema{
   276  				Type:     schema.TypeSet,
   277  				Required: true,
   278  				Set:      originHash,
   279  				Elem: &schema.Resource{
   280  					Schema: map[string]*schema.Schema{
   281  						"custom_origin_config": &schema.Schema{
   282  							Type:          schema.TypeSet,
   283  							Optional:      true,
   284  							ConflictsWith: []string{"origin.s3_origin_config"},
   285  							Set:           customOriginConfigHash,
   286  							MaxItems:      1,
   287  							Elem: &schema.Resource{
   288  								Schema: map[string]*schema.Schema{
   289  									"http_port": &schema.Schema{
   290  										Type:     schema.TypeInt,
   291  										Required: true,
   292  									},
   293  									"https_port": &schema.Schema{
   294  										Type:     schema.TypeInt,
   295  										Required: true,
   296  									},
   297  									"origin_protocol_policy": &schema.Schema{
   298  										Type:     schema.TypeString,
   299  										Required: true,
   300  									},
   301  									"origin_ssl_protocols": &schema.Schema{
   302  										Type:     schema.TypeList,
   303  										Required: true,
   304  										Elem:     &schema.Schema{Type: schema.TypeString},
   305  									},
   306  								},
   307  							},
   308  						},
   309  						"domain_name": &schema.Schema{
   310  							Type:     schema.TypeString,
   311  							Required: true,
   312  						},
   313  						"custom_header": &schema.Schema{
   314  							Type:     schema.TypeSet,
   315  							Optional: true,
   316  							Set:      originCustomHeaderHash,
   317  							Elem: &schema.Resource{
   318  								Schema: map[string]*schema.Schema{
   319  									"name": &schema.Schema{
   320  										Type:     schema.TypeString,
   321  										Required: true,
   322  									},
   323  									"value": &schema.Schema{
   324  										Type:     schema.TypeString,
   325  										Required: true,
   326  									},
   327  								},
   328  							},
   329  						},
   330  						"origin_id": &schema.Schema{
   331  							Type:     schema.TypeString,
   332  							Required: true,
   333  						},
   334  						"origin_path": &schema.Schema{
   335  							Type:     schema.TypeString,
   336  							Optional: true,
   337  						},
   338  						"s3_origin_config": &schema.Schema{
   339  							Type:          schema.TypeSet,
   340  							Optional:      true,
   341  							ConflictsWith: []string{"origin.custom_origin_config"},
   342  							Set:           s3OriginConfigHash,
   343  							MaxItems:      1,
   344  							Elem: &schema.Resource{
   345  								Schema: map[string]*schema.Schema{
   346  									"origin_access_identity": &schema.Schema{
   347  										Type:     schema.TypeString,
   348  										Optional: true,
   349  										Default:  "",
   350  									},
   351  								},
   352  							},
   353  						},
   354  					},
   355  				},
   356  			},
   357  			"price_class": &schema.Schema{
   358  				Type:     schema.TypeString,
   359  				Optional: true,
   360  				Default:  "PriceClass_All",
   361  			},
   362  			"restrictions": &schema.Schema{
   363  				Type:     schema.TypeSet,
   364  				Required: true,
   365  				Set:      restrictionsHash,
   366  				MaxItems: 1,
   367  				Elem: &schema.Resource{
   368  					Schema: map[string]*schema.Schema{
   369  						"geo_restriction": &schema.Schema{
   370  							Type:     schema.TypeSet,
   371  							Required: true,
   372  							Set:      geoRestrictionHash,
   373  							MaxItems: 1,
   374  							Elem: &schema.Resource{
   375  								Schema: map[string]*schema.Schema{
   376  									"locations": &schema.Schema{
   377  										Type:     schema.TypeList,
   378  										Optional: true,
   379  										Elem:     &schema.Schema{Type: schema.TypeString},
   380  									},
   381  									"restriction_type": &schema.Schema{
   382  										Type:     schema.TypeString,
   383  										Required: true,
   384  									},
   385  								},
   386  							},
   387  						},
   388  					},
   389  				},
   390  			},
   391  			"viewer_certificate": &schema.Schema{
   392  				Type:     schema.TypeSet,
   393  				Required: true,
   394  				Set:      viewerCertificateHash,
   395  				MaxItems: 1,
   396  				Elem: &schema.Resource{
   397  					Schema: map[string]*schema.Schema{
   398  						"acm_certificate_arn": &schema.Schema{
   399  							Type:          schema.TypeString,
   400  							Optional:      true,
   401  							ConflictsWith: []string{"viewer_certificate.cloudfront_default_certificate", "viewer_certificate.iam_certificate_id"},
   402  						},
   403  						"cloudfront_default_certificate": &schema.Schema{
   404  							Type:          schema.TypeBool,
   405  							Optional:      true,
   406  							ConflictsWith: []string{"viewer_certificate.acm_certificate_arn", "viewer_certificate.iam_certificate_id"},
   407  						},
   408  						"iam_certificate_id": &schema.Schema{
   409  							Type:          schema.TypeString,
   410  							Optional:      true,
   411  							ConflictsWith: []string{"viewer_certificate.acm_certificate_arn", "viewer_certificate.cloudfront_default_certificate"},
   412  						},
   413  						"minimum_protocol_version": &schema.Schema{
   414  							Type:     schema.TypeString,
   415  							Optional: true,
   416  							Default:  "SSLv3",
   417  						},
   418  						"ssl_support_method": &schema.Schema{
   419  							Type:     schema.TypeString,
   420  							Optional: true,
   421  						},
   422  					},
   423  				},
   424  			},
   425  			"web_acl_id": &schema.Schema{
   426  				Type:     schema.TypeString,
   427  				Optional: true,
   428  			},
   429  			"caller_reference": &schema.Schema{
   430  				Type:     schema.TypeString,
   431  				Computed: true,
   432  			},
   433  			"status": &schema.Schema{
   434  				Type:     schema.TypeString,
   435  				Computed: true,
   436  			},
   437  			"active_trusted_signers": &schema.Schema{
   438  				Type:     schema.TypeMap,
   439  				Computed: true,
   440  			},
   441  			"domain_name": &schema.Schema{
   442  				Type:     schema.TypeString,
   443  				Computed: true,
   444  			},
   445  			"last_modified_time": &schema.Schema{
   446  				Type:     schema.TypeString,
   447  				Computed: true,
   448  			},
   449  			"in_progress_validation_batches": &schema.Schema{
   450  				Type:     schema.TypeInt,
   451  				Computed: true,
   452  			},
   453  			"etag": &schema.Schema{
   454  				Type:     schema.TypeString,
   455  				Computed: true,
   456  			},
   457  			"hosted_zone_id": &schema.Schema{
   458  				Type:     schema.TypeString,
   459  				Computed: true,
   460  			},
   461  			// retain_on_delete is a non-API attribute that may help facilitate speedy
   462  			// deletion of a resoruce. It's mainly here for testing purposes, so
   463  			// enable at your own risk.
   464  			"retain_on_delete": &schema.Schema{
   465  				Type:     schema.TypeBool,
   466  				Optional: true,
   467  				Default:  false,
   468  			},
   469  		},
   470  	}
   471  }
   472  
   473  func resourceAwsCloudFrontDistributionCreate(d *schema.ResourceData, meta interface{}) error {
   474  	conn := meta.(*AWSClient).cloudfrontconn
   475  	params := &cloudfront.CreateDistributionInput{
   476  		DistributionConfig: expandDistributionConfig(d),
   477  	}
   478  
   479  	resp, err := conn.CreateDistribution(params)
   480  	if err != nil {
   481  		return err
   482  	}
   483  	d.SetId(*resp.Distribution.Id)
   484  	return resourceAwsCloudFrontDistributionRead(d, meta)
   485  }
   486  
   487  func resourceAwsCloudFrontDistributionRead(d *schema.ResourceData, meta interface{}) error {
   488  	conn := meta.(*AWSClient).cloudfrontconn
   489  	params := &cloudfront.GetDistributionInput{
   490  		Id: aws.String(d.Id()),
   491  	}
   492  
   493  	resp, err := conn.GetDistribution(params)
   494  	if err != nil {
   495  		return err
   496  	}
   497  
   498  	// Update attributes from DistributionConfig
   499  	err = flattenDistributionConfig(d, resp.Distribution.DistributionConfig)
   500  	if err != nil {
   501  		return err
   502  	}
   503  	// Update other attributes outside of DistributionConfig
   504  	d.SetId(*resp.Distribution.Id)
   505  	err = d.Set("active_trusted_signers", flattenActiveTrustedSigners(resp.Distribution.ActiveTrustedSigners))
   506  	if err != nil {
   507  		return err
   508  	}
   509  	d.Set("status", resp.Distribution.Status)
   510  	d.Set("domain_name", resp.Distribution.DomainName)
   511  	d.Set("last_modified_time", aws.String(resp.Distribution.LastModifiedTime.String()))
   512  	d.Set("in_progress_validation_batches", resp.Distribution.InProgressInvalidationBatches)
   513  	d.Set("etag", resp.ETag)
   514  	return nil
   515  }
   516  
   517  func resourceAwsCloudFrontDistributionUpdate(d *schema.ResourceData, meta interface{}) error {
   518  	conn := meta.(*AWSClient).cloudfrontconn
   519  	params := &cloudfront.UpdateDistributionInput{
   520  		Id:                 aws.String(d.Id()),
   521  		DistributionConfig: expandDistributionConfig(d),
   522  		IfMatch:            aws.String(d.Get("etag").(string)),
   523  	}
   524  	_, err := conn.UpdateDistribution(params)
   525  	if err != nil {
   526  		return err
   527  	}
   528  
   529  	return resourceAwsCloudFrontDistributionRead(d, meta)
   530  }
   531  
   532  func resourceAwsCloudFrontDistributionDelete(d *schema.ResourceData, meta interface{}) error {
   533  	conn := meta.(*AWSClient).cloudfrontconn
   534  
   535  	// manually disable the distribution first
   536  	d.Set("enabled", false)
   537  	err := resourceAwsCloudFrontDistributionUpdate(d, meta)
   538  	if err != nil {
   539  		return err
   540  	}
   541  
   542  	// skip delete if retain_on_delete is enabled
   543  	if d.Get("retain_on_delete").(bool) {
   544  		log.Printf("[WARN] Removing Distribtuion ID %s with retain_on_delete set. Please delete this distribution manually.", d.Id())
   545  		d.SetId("")
   546  		return nil
   547  	}
   548  
   549  	// Distribution needs to be in deployed state again before it can be deleted.
   550  	err = resourceAwsCloudFrontDistributionWaitUntilDeployed(d.Id(), meta)
   551  	if err != nil {
   552  		return err
   553  	}
   554  
   555  	// now delete
   556  	params := &cloudfront.DeleteDistributionInput{
   557  		Id:      aws.String(d.Id()),
   558  		IfMatch: aws.String(d.Get("etag").(string)),
   559  	}
   560  
   561  	_, err = conn.DeleteDistribution(params)
   562  	if err != nil {
   563  		return err
   564  	}
   565  
   566  	// Done
   567  	d.SetId("")
   568  	return nil
   569  }
   570  
   571  // resourceAwsCloudFrontWebDistributionWaitUntilDeployed blocks until the
   572  // distribution is deployed. It currently takes exactly 15 minutes to deploy
   573  // but that might change in the future.
   574  func resourceAwsCloudFrontDistributionWaitUntilDeployed(id string, meta interface{}) error {
   575  	stateConf := &resource.StateChangeConf{
   576  		Pending:    []string{"InProgress", "Deployed"},
   577  		Target:     []string{"Deployed"},
   578  		Refresh:    resourceAwsCloudFrontWebDistributionStateRefreshFunc(id, meta),
   579  		Timeout:    40 * time.Minute,
   580  		MinTimeout: 15 * time.Second,
   581  		Delay:      10 * time.Minute,
   582  	}
   583  
   584  	_, err := stateConf.WaitForState()
   585  	return err
   586  }
   587  
   588  // The refresh function for resourceAwsCloudFrontWebDistributionWaitUntilDeployed.
   589  func resourceAwsCloudFrontWebDistributionStateRefreshFunc(id string, meta interface{}) resource.StateRefreshFunc {
   590  	return func() (interface{}, string, error) {
   591  		conn := meta.(*AWSClient).cloudfrontconn
   592  		params := &cloudfront.GetDistributionInput{
   593  			Id: aws.String(id),
   594  		}
   595  
   596  		resp, err := conn.GetDistribution(params)
   597  		if err != nil {
   598  			log.Printf("Error on retrieving CloudFront distribution when waiting: %s", err)
   599  			return nil, "", err
   600  		}
   601  
   602  		if resp == nil {
   603  			return nil, "", nil
   604  		}
   605  
   606  		return resp.Distribution, *resp.Distribution.Status, nil
   607  	}
   608  }