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