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 }