github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/aws/resource_aws_elastic_transcoder_pipeline.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"regexp"
     7  
     8  	"github.com/aws/aws-sdk-go/aws"
     9  	"github.com/aws/aws-sdk-go/aws/awserr"
    10  	"github.com/aws/aws-sdk-go/service/elastictranscoder"
    11  	"github.com/hashicorp/terraform/helper/resource"
    12  	"github.com/hashicorp/terraform/helper/schema"
    13  )
    14  
    15  func resourceAwsElasticTranscoderPipeline() *schema.Resource {
    16  	return &schema.Resource{
    17  		Create: resourceAwsElasticTranscoderPipelineCreate,
    18  		Read:   resourceAwsElasticTranscoderPipelineRead,
    19  		Update: resourceAwsElasticTranscoderPipelineUpdate,
    20  		Delete: resourceAwsElasticTranscoderPipelineDelete,
    21  
    22  		Schema: map[string]*schema.Schema{
    23  			"arn": {
    24  				Type:     schema.TypeString,
    25  				Computed: true,
    26  			},
    27  
    28  			"aws_kms_key_arn": {
    29  				Type:         schema.TypeString,
    30  				Optional:     true,
    31  				ValidateFunc: validateArn,
    32  			},
    33  
    34  			// ContentConfig also requires ThumbnailConfig
    35  			"content_config": {
    36  				Type:     schema.TypeSet,
    37  				Optional: true,
    38  				Computed: true,
    39  				MaxItems: 1,
    40  				Elem: &schema.Resource{
    41  					// elastictranscoder.PipelineOutputConfig
    42  					Schema: map[string]*schema.Schema{
    43  						"bucket": {
    44  							Type:     schema.TypeString,
    45  							Optional: true,
    46  							// AWS may insert the bucket name here taken from output_bucket
    47  							Computed: true,
    48  						},
    49  						"storage_class": {
    50  							Type:     schema.TypeString,
    51  							Optional: true,
    52  						},
    53  					},
    54  				},
    55  			},
    56  
    57  			"content_config_permissions": {
    58  				Type:     schema.TypeSet,
    59  				Optional: true,
    60  				Elem: &schema.Resource{
    61  					Schema: map[string]*schema.Schema{
    62  						"access": {
    63  							Type:     schema.TypeList,
    64  							Optional: true,
    65  							Elem:     &schema.Schema{Type: schema.TypeString},
    66  						},
    67  						"grantee": {
    68  							Type:     schema.TypeString,
    69  							Optional: true,
    70  						},
    71  						"grantee_type": {
    72  							Type:     schema.TypeString,
    73  							Optional: true,
    74  						},
    75  					},
    76  				},
    77  			},
    78  
    79  			"input_bucket": {
    80  				Type:     schema.TypeString,
    81  				Required: true,
    82  			},
    83  
    84  			"name": {
    85  				Type:     schema.TypeString,
    86  				Optional: true,
    87  				Computed: true,
    88  				ForceNew: true,
    89  				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
    90  					value := v.(string)
    91  					if !regexp.MustCompile(`^[.0-9A-Za-z-_]+$`).MatchString(value) {
    92  						errors = append(errors, fmt.Errorf(
    93  							"only alphanumeric characters, hyphens, underscores, and periods allowed in %q", k))
    94  					}
    95  					if len(value) > 40 {
    96  						errors = append(errors, fmt.Errorf("%q cannot be longer than 40 characters", k))
    97  					}
    98  					return
    99  				},
   100  			},
   101  
   102  			"notifications": {
   103  				Type:     schema.TypeSet,
   104  				Optional: true,
   105  				MaxItems: 1,
   106  				Elem: &schema.Resource{
   107  					Schema: map[string]*schema.Schema{
   108  						"completed": {
   109  							Type:     schema.TypeString,
   110  							Optional: true,
   111  						},
   112  						"error": {
   113  							Type:     schema.TypeString,
   114  							Optional: true,
   115  						},
   116  						"progressing": {
   117  							Type:     schema.TypeString,
   118  							Optional: true,
   119  						},
   120  						"warning": {
   121  							Type:     schema.TypeString,
   122  							Optional: true,
   123  						},
   124  					},
   125  				},
   126  			},
   127  
   128  			// The output_bucket must be set, or both of content_config.bucket
   129  			// and thumbnail_config.bucket.
   130  			// This is set as Computed, because the API may or may not return
   131  			// this as set based on the other 2 configurations.
   132  			"output_bucket": {
   133  				Type:     schema.TypeString,
   134  				Optional: true,
   135  				Computed: true,
   136  			},
   137  
   138  			"role": {
   139  				Type:     schema.TypeString,
   140  				Required: true,
   141  			},
   142  
   143  			"thumbnail_config": {
   144  				Type:     schema.TypeSet,
   145  				Optional: true,
   146  				Computed: true,
   147  				MaxItems: 1,
   148  				Elem: &schema.Resource{
   149  					// elastictranscoder.PipelineOutputConfig
   150  					Schema: map[string]*schema.Schema{
   151  						"bucket": {
   152  							Type:     schema.TypeString,
   153  							Optional: true,
   154  							// AWS may insert the bucket name here taken from output_bucket
   155  							Computed: true,
   156  						},
   157  						"storage_class": {
   158  							Type:     schema.TypeString,
   159  							Optional: true,
   160  						},
   161  					},
   162  				},
   163  			},
   164  
   165  			"thumbnail_config_permissions": {
   166  				Type:     schema.TypeSet,
   167  				Optional: true,
   168  				Elem: &schema.Resource{
   169  					Schema: map[string]*schema.Schema{
   170  						"access": {
   171  							Type:     schema.TypeList,
   172  							Optional: true,
   173  							Elem:     &schema.Schema{Type: schema.TypeString},
   174  						},
   175  						"grantee": {
   176  							Type:     schema.TypeString,
   177  							Optional: true,
   178  						},
   179  						"grantee_type": {
   180  							Type:     schema.TypeString,
   181  							Optional: true,
   182  						},
   183  					},
   184  				},
   185  			},
   186  		},
   187  	}
   188  }
   189  
   190  func resourceAwsElasticTranscoderPipelineCreate(d *schema.ResourceData, meta interface{}) error {
   191  	elastictranscoderconn := meta.(*AWSClient).elastictranscoderconn
   192  
   193  	req := &elastictranscoder.CreatePipelineInput{
   194  		AwsKmsKeyArn:    getStringPtr(d, "aws_kms_key_arn"),
   195  		ContentConfig:   expandETPiplineOutputConfig(d, "content_config"),
   196  		InputBucket:     aws.String(d.Get("input_bucket").(string)),
   197  		Notifications:   expandETNotifications(d),
   198  		OutputBucket:    getStringPtr(d, "output_bucket"),
   199  		Role:            getStringPtr(d, "role"),
   200  		ThumbnailConfig: expandETPiplineOutputConfig(d, "thumbnail_config"),
   201  	}
   202  
   203  	if name, ok := d.GetOk("name"); ok {
   204  		req.Name = aws.String(name.(string))
   205  	} else {
   206  		name := resource.PrefixedUniqueId("tf-et-")
   207  		d.Set("name", name)
   208  		req.Name = aws.String(name)
   209  	}
   210  
   211  	if (req.OutputBucket == nil && (req.ContentConfig == nil || req.ContentConfig.Bucket == nil)) ||
   212  		(req.OutputBucket != nil && req.ContentConfig != nil && req.ContentConfig.Bucket != nil) {
   213  		return fmt.Errorf("[ERROR] you must specify only one of output_bucket or content_config.bucket")
   214  	}
   215  
   216  	log.Printf("[DEBUG] Elastic Transcoder Pipeline create opts: %s", req)
   217  	resp, err := elastictranscoderconn.CreatePipeline(req)
   218  	if err != nil {
   219  		return fmt.Errorf("Error creating Elastic Transcoder Pipeline: %s", err)
   220  	}
   221  
   222  	d.SetId(*resp.Pipeline.Id)
   223  
   224  	for _, w := range resp.Warnings {
   225  		log.Printf("[WARN] Elastic Transcoder Pipeline %v: %v", *w.Code, *w.Message)
   226  	}
   227  
   228  	return resourceAwsElasticTranscoderPipelineRead(d, meta)
   229  }
   230  
   231  func expandETNotifications(d *schema.ResourceData) *elastictranscoder.Notifications {
   232  	set, ok := d.GetOk("notifications")
   233  	if !ok {
   234  		return nil
   235  	}
   236  
   237  	s := set.(*schema.Set).List()
   238  	if s == nil || len(s) == 0 {
   239  		return nil
   240  	}
   241  
   242  	if s[0] == nil {
   243  		log.Printf("[ERR] First element of Notifications set is nil")
   244  		return nil
   245  	}
   246  
   247  	rN := s[0].(map[string]interface{})
   248  
   249  	return &elastictranscoder.Notifications{
   250  		Completed:   aws.String(rN["completed"].(string)),
   251  		Error:       aws.String(rN["error"].(string)),
   252  		Progressing: aws.String(rN["progressing"].(string)),
   253  		Warning:     aws.String(rN["warning"].(string)),
   254  	}
   255  }
   256  
   257  func flattenETNotifications(n *elastictranscoder.Notifications) []map[string]interface{} {
   258  	if n == nil {
   259  		return nil
   260  	}
   261  
   262  	allEmpty := func(s ...*string) bool {
   263  		for _, s := range s {
   264  			if s != nil && *s != "" {
   265  				return false
   266  			}
   267  		}
   268  		return true
   269  	}
   270  
   271  	// the API always returns a Notifications value, even when all fields are nil
   272  	if allEmpty(n.Completed, n.Error, n.Progressing, n.Warning) {
   273  		return nil
   274  	}
   275  
   276  	m := setMap(make(map[string]interface{}))
   277  
   278  	m.SetString("completed", n.Completed)
   279  	m.SetString("error", n.Error)
   280  	m.SetString("progressing", n.Progressing)
   281  	m.SetString("warning", n.Warning)
   282  	return m.MapList()
   283  }
   284  
   285  func expandETPiplineOutputConfig(d *schema.ResourceData, key string) *elastictranscoder.PipelineOutputConfig {
   286  	set, ok := d.GetOk(key)
   287  	if !ok {
   288  		return nil
   289  	}
   290  
   291  	s := set.(*schema.Set)
   292  	if s == nil || s.Len() == 0 {
   293  		return nil
   294  	}
   295  
   296  	cc := s.List()[0].(map[string]interface{})
   297  
   298  	cfg := &elastictranscoder.PipelineOutputConfig{
   299  		Bucket:       getStringPtr(cc, "bucket"),
   300  		StorageClass: getStringPtr(cc, "storage_class"),
   301  	}
   302  
   303  	switch key {
   304  	case "content_config":
   305  		cfg.Permissions = expandETPermList(d.Get("content_config_permissions").(*schema.Set))
   306  	case "thumbnail_config":
   307  		cfg.Permissions = expandETPermList(d.Get("thumbnail_config_permissions").(*schema.Set))
   308  	}
   309  
   310  	return cfg
   311  }
   312  
   313  func flattenETPipelineOutputConfig(cfg *elastictranscoder.PipelineOutputConfig) []map[string]interface{} {
   314  	m := setMap(make(map[string]interface{}))
   315  
   316  	m.SetString("bucket", cfg.Bucket)
   317  	m.SetString("storage_class", cfg.StorageClass)
   318  
   319  	return m.MapList()
   320  }
   321  
   322  func expandETPermList(permissions *schema.Set) []*elastictranscoder.Permission {
   323  	var perms []*elastictranscoder.Permission
   324  
   325  	for _, p := range permissions.List() {
   326  		perm := &elastictranscoder.Permission{
   327  			Access:      getStringPtrList(p.(map[string]interface{}), "access"),
   328  			Grantee:     getStringPtr(p, "grantee"),
   329  			GranteeType: getStringPtr(p, "grantee_type"),
   330  		}
   331  		perms = append(perms, perm)
   332  	}
   333  	return perms
   334  }
   335  
   336  func flattenETPermList(perms []*elastictranscoder.Permission) []map[string]interface{} {
   337  	var set []map[string]interface{}
   338  
   339  	for _, p := range perms {
   340  		m := setMap(make(map[string]interface{}))
   341  		m.Set("access", flattenStringList(p.Access))
   342  		m.SetString("grantee", p.Grantee)
   343  		m.SetString("grantee_type", p.GranteeType)
   344  
   345  		set = append(set, m)
   346  	}
   347  	return set
   348  }
   349  
   350  func resourceAwsElasticTranscoderPipelineUpdate(d *schema.ResourceData, meta interface{}) error {
   351  	elastictranscoderconn := meta.(*AWSClient).elastictranscoderconn
   352  
   353  	req := &elastictranscoder.UpdatePipelineInput{
   354  		Id: aws.String(d.Id()),
   355  	}
   356  
   357  	if d.HasChange("aws_kms_key_arn") {
   358  		req.AwsKmsKeyArn = getStringPtr(d, "aws_kms_key_arn")
   359  	}
   360  
   361  	if d.HasChange("content_config") {
   362  		req.ContentConfig = expandETPiplineOutputConfig(d, "content_config")
   363  	}
   364  
   365  	if d.HasChange("input_bucket") {
   366  		req.InputBucket = getStringPtr(d, "input_bucket")
   367  	}
   368  
   369  	if d.HasChange("name") {
   370  		req.Name = getStringPtr(d, "name")
   371  	}
   372  
   373  	if d.HasChange("notifications") {
   374  		req.Notifications = expandETNotifications(d)
   375  	}
   376  
   377  	if d.HasChange("role") {
   378  		req.Role = getStringPtr(d, "role")
   379  	}
   380  
   381  	if d.HasChange("thumbnail_config") {
   382  		req.ThumbnailConfig = expandETPiplineOutputConfig(d, "thumbnail_config")
   383  	}
   384  
   385  	log.Printf("[DEBUG] Updating Elastic Transcoder Pipeline: %#v", req)
   386  	output, err := elastictranscoderconn.UpdatePipeline(req)
   387  	if err != nil {
   388  		return fmt.Errorf("Error updating Elastic Transcoder pipeline: %s", err)
   389  	}
   390  
   391  	for _, w := range output.Warnings {
   392  		log.Printf("[WARN] Elastic Transcoder Pipeline %v: %v", *w.Code, *w.Message)
   393  	}
   394  
   395  	return resourceAwsElasticTranscoderPipelineRead(d, meta)
   396  }
   397  
   398  func resourceAwsElasticTranscoderPipelineRead(d *schema.ResourceData, meta interface{}) error {
   399  	elastictranscoderconn := meta.(*AWSClient).elastictranscoderconn
   400  
   401  	resp, err := elastictranscoderconn.ReadPipeline(&elastictranscoder.ReadPipelineInput{
   402  		Id: aws.String(d.Id()),
   403  	})
   404  
   405  	if err != nil {
   406  		if err, ok := err.(awserr.Error); ok && err.Code() == "ResourceNotFoundException" {
   407  			d.SetId("")
   408  			return nil
   409  		}
   410  		return err
   411  	}
   412  
   413  	log.Printf("[DEBUG] Elastic Transcoder Pipeline Read response: %#v", resp)
   414  
   415  	pipeline := resp.Pipeline
   416  
   417  	d.Set("arn", *pipeline.Arn)
   418  
   419  	if arn := pipeline.AwsKmsKeyArn; arn != nil {
   420  		d.Set("aws_kms_key_arn", *arn)
   421  	}
   422  
   423  	if pipeline.ContentConfig != nil {
   424  		err := d.Set("content_config", flattenETPipelineOutputConfig(pipeline.ContentConfig))
   425  		if err != nil {
   426  			return fmt.Errorf("error setting content_config: %s", err)
   427  		}
   428  
   429  		if pipeline.ContentConfig.Permissions != nil {
   430  			err := d.Set("content_config_permissions", flattenETPermList(pipeline.ContentConfig.Permissions))
   431  			if err != nil {
   432  				return fmt.Errorf("error setting content_config_permissions: %s", err)
   433  			}
   434  		}
   435  	}
   436  
   437  	d.Set("input_bucket", *pipeline.InputBucket)
   438  	d.Set("name", *pipeline.Name)
   439  
   440  	notifications := flattenETNotifications(pipeline.Notifications)
   441  	if notifications != nil {
   442  		if err := d.Set("notifications", notifications); err != nil {
   443  			return fmt.Errorf("error setting notifications: %s", err)
   444  		}
   445  	}
   446  
   447  	d.Set("role", *pipeline.Role)
   448  
   449  	if pipeline.ThumbnailConfig != nil {
   450  		err := d.Set("thumbnail_config", flattenETPipelineOutputConfig(pipeline.ThumbnailConfig))
   451  		if err != nil {
   452  			return fmt.Errorf("error setting thumbnail_config: %s", err)
   453  		}
   454  
   455  		if pipeline.ThumbnailConfig.Permissions != nil {
   456  			err := d.Set("thumbnail_config_permissions", flattenETPermList(pipeline.ThumbnailConfig.Permissions))
   457  			if err != nil {
   458  				return fmt.Errorf("error setting thumbnail_config_permissions: %s", err)
   459  			}
   460  		}
   461  	}
   462  
   463  	if pipeline.OutputBucket != nil {
   464  		d.Set("output_bucket", *pipeline.OutputBucket)
   465  	}
   466  
   467  	return nil
   468  }
   469  
   470  func resourceAwsElasticTranscoderPipelineDelete(d *schema.ResourceData, meta interface{}) error {
   471  	elastictranscoderconn := meta.(*AWSClient).elastictranscoderconn
   472  
   473  	log.Printf("[DEBUG] Elastic Transcoder Delete Pipeline: %s", d.Id())
   474  	_, err := elastictranscoderconn.DeletePipeline(&elastictranscoder.DeletePipelineInput{
   475  		Id: aws.String(d.Id()),
   476  	})
   477  	if err != nil {
   478  		return fmt.Errorf("error deleting Elastic Transcoder Pipeline: %s", err)
   479  	}
   480  	return nil
   481  }