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 }