github.com/cbroglie/terraform@v0.7.0-rc3.0.20170410193827-735dfc416d46/builtin/providers/aws/resource_aws_emr_cluster.go (about) 1 package aws 2 3 import ( 4 "log" 5 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "net/http" 10 "strings" 11 "time" 12 13 "github.com/aws/aws-sdk-go/aws" 14 "github.com/aws/aws-sdk-go/aws/awserr" 15 "github.com/aws/aws-sdk-go/service/emr" 16 "github.com/hashicorp/terraform/helper/resource" 17 "github.com/hashicorp/terraform/helper/schema" 18 ) 19 20 func resourceAwsEMRCluster() *schema.Resource { 21 return &schema.Resource{ 22 Create: resourceAwsEMRClusterCreate, 23 Read: resourceAwsEMRClusterRead, 24 Update: resourceAwsEMRClusterUpdate, 25 Delete: resourceAwsEMRClusterDelete, 26 Schema: map[string]*schema.Schema{ 27 "name": { 28 Type: schema.TypeString, 29 ForceNew: true, 30 Required: true, 31 }, 32 "release_label": { 33 Type: schema.TypeString, 34 ForceNew: true, 35 Required: true, 36 }, 37 "master_instance_type": { 38 Type: schema.TypeString, 39 Required: true, 40 ForceNew: true, 41 }, 42 "core_instance_type": { 43 Type: schema.TypeString, 44 Optional: true, 45 ForceNew: true, 46 Computed: true, 47 }, 48 "core_instance_count": { 49 Type: schema.TypeInt, 50 Optional: true, 51 Default: 1, 52 }, 53 "cluster_state": { 54 Type: schema.TypeString, 55 Computed: true, 56 }, 57 "log_uri": { 58 Type: schema.TypeString, 59 ForceNew: true, 60 Optional: true, 61 }, 62 "master_public_dns": { 63 Type: schema.TypeString, 64 Computed: true, 65 }, 66 "applications": { 67 Type: schema.TypeSet, 68 Optional: true, 69 ForceNew: true, 70 Elem: &schema.Schema{Type: schema.TypeString}, 71 Set: schema.HashString, 72 }, 73 "termination_protection": { 74 Type: schema.TypeBool, 75 Optional: true, 76 Computed: true, 77 }, 78 "keep_job_flow_alive_when_no_steps": { 79 Type: schema.TypeBool, 80 ForceNew: true, 81 Optional: true, 82 Computed: true, 83 }, 84 "ec2_attributes": { 85 Type: schema.TypeList, 86 MaxItems: 1, 87 Optional: true, 88 ForceNew: true, 89 Elem: &schema.Resource{ 90 Schema: map[string]*schema.Schema{ 91 "key_name": { 92 Type: schema.TypeString, 93 Optional: true, 94 }, 95 "subnet_id": { 96 Type: schema.TypeString, 97 Optional: true, 98 }, 99 "additional_master_security_groups": { 100 Type: schema.TypeString, 101 Optional: true, 102 }, 103 "additional_slave_security_groups": { 104 Type: schema.TypeString, 105 Optional: true, 106 }, 107 "emr_managed_master_security_group": { 108 Type: schema.TypeString, 109 Optional: true, 110 }, 111 "emr_managed_slave_security_group": { 112 Type: schema.TypeString, 113 Optional: true, 114 }, 115 "instance_profile": { 116 Type: schema.TypeString, 117 Required: true, 118 }, 119 "service_access_security_group": { 120 Type: schema.TypeString, 121 Optional: true, 122 }, 123 }, 124 }, 125 }, 126 "bootstrap_action": { 127 Type: schema.TypeSet, 128 Optional: true, 129 ForceNew: true, 130 Elem: &schema.Resource{ 131 Schema: map[string]*schema.Schema{ 132 "name": { 133 Type: schema.TypeString, 134 Required: true, 135 }, 136 "path": { 137 Type: schema.TypeString, 138 Required: true, 139 }, 140 "args": { 141 Type: schema.TypeSet, 142 Optional: true, 143 Elem: &schema.Schema{Type: schema.TypeString}, 144 Set: schema.HashString, 145 }, 146 }, 147 }, 148 }, 149 "tags": tagsSchema(), 150 "configurations": { 151 Type: schema.TypeString, 152 ForceNew: true, 153 Optional: true, 154 }, 155 "service_role": { 156 Type: schema.TypeString, 157 ForceNew: true, 158 Required: true, 159 }, 160 "autoscaling_role": &schema.Schema{ 161 Type: schema.TypeString, 162 ForceNew: true, 163 Optional: true, 164 }, 165 "visible_to_all_users": { 166 Type: schema.TypeBool, 167 Optional: true, 168 Default: true, 169 }, 170 }, 171 } 172 } 173 174 func resourceAwsEMRClusterCreate(d *schema.ResourceData, meta interface{}) error { 175 conn := meta.(*AWSClient).emrconn 176 177 log.Printf("[DEBUG] Creating EMR cluster") 178 masterInstanceType := d.Get("master_instance_type").(string) 179 coreInstanceType := masterInstanceType 180 if v, ok := d.GetOk("core_instance_type"); ok { 181 coreInstanceType = v.(string) 182 } 183 coreInstanceCount := d.Get("core_instance_count").(int) 184 185 applications := d.Get("applications").(*schema.Set).List() 186 187 keepJobFlowAliveWhenNoSteps := true 188 if v, ok := d.GetOk("keep_job_flow_alive_when_no_steps"); ok { 189 keepJobFlowAliveWhenNoSteps = v.(bool) 190 } 191 192 terminationProtection := false 193 if v, ok := d.GetOk("termination_protection"); ok { 194 terminationProtection = v.(bool) 195 } 196 instanceConfig := &emr.JobFlowInstancesConfig{ 197 MasterInstanceType: aws.String(masterInstanceType), 198 SlaveInstanceType: aws.String(coreInstanceType), 199 InstanceCount: aws.Int64(int64(coreInstanceCount)), 200 201 KeepJobFlowAliveWhenNoSteps: aws.Bool(keepJobFlowAliveWhenNoSteps), 202 TerminationProtected: aws.Bool(terminationProtection), 203 } 204 205 var instanceProfile string 206 if a, ok := d.GetOk("ec2_attributes"); ok { 207 ec2Attributes := a.([]interface{}) 208 attributes := ec2Attributes[0].(map[string]interface{}) 209 210 if v, ok := attributes["key_name"]; ok { 211 instanceConfig.Ec2KeyName = aws.String(v.(string)) 212 } 213 if v, ok := attributes["subnet_id"]; ok { 214 instanceConfig.Ec2SubnetId = aws.String(v.(string)) 215 } 216 if v, ok := attributes["subnet_id"]; ok { 217 instanceConfig.Ec2SubnetId = aws.String(v.(string)) 218 } 219 220 if v, ok := attributes["additional_master_security_groups"]; ok { 221 strSlice := strings.Split(v.(string), ",") 222 for i, s := range strSlice { 223 strSlice[i] = strings.TrimSpace(s) 224 } 225 instanceConfig.AdditionalMasterSecurityGroups = aws.StringSlice(strSlice) 226 } 227 228 if v, ok := attributes["additional_slave_security_groups"]; ok { 229 strSlice := strings.Split(v.(string), ",") 230 for i, s := range strSlice { 231 strSlice[i] = strings.TrimSpace(s) 232 } 233 instanceConfig.AdditionalSlaveSecurityGroups = aws.StringSlice(strSlice) 234 } 235 236 if v, ok := attributes["emr_managed_master_security_group"]; ok { 237 instanceConfig.EmrManagedMasterSecurityGroup = aws.String(v.(string)) 238 } 239 if v, ok := attributes["emr_managed_slave_security_group"]; ok { 240 instanceConfig.EmrManagedSlaveSecurityGroup = aws.String(v.(string)) 241 } 242 243 if len(strings.TrimSpace(attributes["instance_profile"].(string))) != 0 { 244 instanceProfile = strings.TrimSpace(attributes["instance_profile"].(string)) 245 } 246 247 if v, ok := attributes["service_access_security_group"]; ok { 248 instanceConfig.ServiceAccessSecurityGroup = aws.String(v.(string)) 249 } 250 } 251 252 emrApps := expandApplications(applications) 253 254 params := &emr.RunJobFlowInput{ 255 Instances: instanceConfig, 256 Name: aws.String(d.Get("name").(string)), 257 Applications: emrApps, 258 259 ReleaseLabel: aws.String(d.Get("release_label").(string)), 260 ServiceRole: aws.String(d.Get("service_role").(string)), 261 VisibleToAllUsers: aws.Bool(d.Get("visible_to_all_users").(bool)), 262 } 263 264 if v, ok := d.GetOk("log_uri"); ok { 265 params.LogUri = aws.String(v.(string)) 266 } 267 if v, ok := d.GetOk("autoscaling_role"); ok { 268 params.AutoScalingRole = aws.String(v.(string)) 269 } 270 271 if instanceProfile != "" { 272 params.JobFlowRole = aws.String(instanceProfile) 273 } 274 275 if v, ok := d.GetOk("bootstrap_action"); ok { 276 bootstrapActions := v.(*schema.Set).List() 277 params.BootstrapActions = expandBootstrapActions(bootstrapActions) 278 } 279 if v, ok := d.GetOk("tags"); ok { 280 tagsIn := v.(map[string]interface{}) 281 params.Tags = expandTags(tagsIn) 282 } 283 if v, ok := d.GetOk("configurations"); ok { 284 confUrl := v.(string) 285 params.Configurations = expandConfigures(confUrl) 286 } 287 288 log.Printf("[DEBUG] EMR Cluster create options: %s", params) 289 resp, err := conn.RunJobFlow(params) 290 291 if err != nil { 292 log.Printf("[ERROR] %s", err) 293 return err 294 } 295 296 d.SetId(*resp.JobFlowId) 297 298 log.Println( 299 "[INFO] Waiting for EMR Cluster to be available") 300 301 stateConf := &resource.StateChangeConf{ 302 Pending: []string{"STARTING", "BOOTSTRAPPING"}, 303 Target: []string{"WAITING", "RUNNING"}, 304 Refresh: resourceAwsEMRClusterStateRefreshFunc(d, meta), 305 Timeout: 75 * time.Minute, 306 MinTimeout: 10 * time.Second, 307 Delay: 30 * time.Second, // Wait 30 secs before starting 308 } 309 310 _, err = stateConf.WaitForState() 311 if err != nil { 312 return fmt.Errorf("[WARN] Error waiting for EMR Cluster state to be \"WAITING\" or \"RUNNING\": %s", err) 313 } 314 315 return resourceAwsEMRClusterRead(d, meta) 316 } 317 318 func resourceAwsEMRClusterRead(d *schema.ResourceData, meta interface{}) error { 319 emrconn := meta.(*AWSClient).emrconn 320 321 req := &emr.DescribeClusterInput{ 322 ClusterId: aws.String(d.Id()), 323 } 324 325 resp, err := emrconn.DescribeCluster(req) 326 if err != nil { 327 return fmt.Errorf("Error reading EMR cluster: %s", err) 328 } 329 330 if resp.Cluster == nil { 331 log.Printf("[DEBUG] EMR Cluster (%s) not found", d.Id()) 332 d.SetId("") 333 return nil 334 } 335 336 cluster := resp.Cluster 337 338 if cluster.Status != nil { 339 if *cluster.Status.State == "TERMINATED" { 340 log.Printf("[DEBUG] EMR Cluster (%s) was TERMINATED already", d.Id()) 341 d.SetId("") 342 return nil 343 } 344 345 if *cluster.Status.State == "TERMINATED_WITH_ERRORS" { 346 log.Printf("[DEBUG] EMR Cluster (%s) was TERMINATED_WITH_ERRORS already", d.Id()) 347 d.SetId("") 348 return nil 349 } 350 351 d.Set("cluster_state", cluster.Status.State) 352 } 353 354 instanceGroups, err := fetchAllEMRInstanceGroups(meta, d.Id()) 355 if err == nil { 356 coreGroup := findGroup(instanceGroups, "CORE") 357 if coreGroup != nil { 358 d.Set("core_instance_type", coreGroup.InstanceType) 359 } 360 } 361 362 d.Set("name", cluster.Name) 363 d.Set("service_role", cluster.ServiceRole) 364 d.Set("autoscaling_role", cluster.AutoScalingRole) 365 d.Set("release_label", cluster.ReleaseLabel) 366 d.Set("log_uri", cluster.LogUri) 367 d.Set("master_public_dns", cluster.MasterPublicDnsName) 368 d.Set("visible_to_all_users", cluster.VisibleToAllUsers) 369 d.Set("tags", tagsToMapEMR(cluster.Tags)) 370 371 if err := d.Set("applications", flattenApplications(cluster.Applications)); err != nil { 372 log.Printf("[ERR] Error setting EMR Applications for cluster (%s): %s", d.Id(), err) 373 } 374 375 // Configurations is a JSON document. It's built with an expand method but a 376 // simple string should be returned as JSON 377 if err := d.Set("configurations", cluster.Configurations); err != nil { 378 log.Printf("[ERR] Error setting EMR configurations for cluster (%s): %s", d.Id(), err) 379 } 380 381 if err := d.Set("ec2_attributes", flattenEc2Attributes(cluster.Ec2InstanceAttributes)); err != nil { 382 log.Printf("[ERR] Error setting EMR Ec2 Attributes: %s", err) 383 } 384 return nil 385 } 386 387 func resourceAwsEMRClusterUpdate(d *schema.ResourceData, meta interface{}) error { 388 conn := meta.(*AWSClient).emrconn 389 390 d.Partial(true) 391 392 if d.HasChange("core_instance_count") { 393 d.SetPartial("core_instance_count") 394 log.Printf("[DEBUG] Modify EMR cluster") 395 groups, err := fetchAllEMRInstanceGroups(meta, d.Id()) 396 if err != nil { 397 log.Printf("[DEBUG] Error finding all instance groups: %s", err) 398 return err 399 } 400 401 coreInstanceCount := d.Get("core_instance_count").(int) 402 coreGroup := findGroup(groups, "CORE") 403 if coreGroup == nil { 404 return fmt.Errorf("[ERR] Error finding core group") 405 } 406 407 params := &emr.ModifyInstanceGroupsInput{ 408 InstanceGroups: []*emr.InstanceGroupModifyConfig{ 409 { 410 InstanceGroupId: coreGroup.Id, 411 InstanceCount: aws.Int64(int64(coreInstanceCount) - 1), 412 }, 413 }, 414 } 415 _, errModify := conn.ModifyInstanceGroups(params) 416 if errModify != nil { 417 log.Printf("[ERROR] %s", errModify) 418 return errModify 419 } 420 421 log.Printf("[DEBUG] Modify EMR Cluster done...") 422 423 log.Println("[INFO] Waiting for EMR Cluster to be available") 424 425 stateConf := &resource.StateChangeConf{ 426 Pending: []string{"STARTING", "BOOTSTRAPPING"}, 427 Target: []string{"WAITING", "RUNNING"}, 428 Refresh: resourceAwsEMRClusterStateRefreshFunc(d, meta), 429 Timeout: 40 * time.Minute, 430 MinTimeout: 10 * time.Second, 431 Delay: 5 * time.Second, 432 } 433 434 _, err = stateConf.WaitForState() 435 if err != nil { 436 return fmt.Errorf("[WARN] Error waiting for EMR Cluster state to be \"WAITING\" or \"RUNNING\" after modification: %s", err) 437 } 438 } 439 440 if d.HasChange("visible_to_all_users") { 441 d.SetPartial("visible_to_all_users") 442 _, errModify := conn.SetVisibleToAllUsers(&emr.SetVisibleToAllUsersInput{ 443 JobFlowIds: []*string{aws.String(d.Id())}, 444 VisibleToAllUsers: aws.Bool(d.Get("visible_to_all_users").(bool)), 445 }) 446 if errModify != nil { 447 log.Printf("[ERROR] %s", errModify) 448 return errModify 449 } 450 } 451 452 if d.HasChange("termination_protection") { 453 d.SetPartial("termination_protection") 454 _, errModify := conn.SetTerminationProtection(&emr.SetTerminationProtectionInput{ 455 JobFlowIds: []*string{aws.String(d.Id())}, 456 TerminationProtected: aws.Bool(d.Get("termination_protection").(bool)), 457 }) 458 if errModify != nil { 459 log.Printf("[ERROR] %s", errModify) 460 return errModify 461 } 462 } 463 464 if err := setTagsEMR(conn, d); err != nil { 465 return err 466 } else { 467 d.SetPartial("tags") 468 } 469 470 d.Partial(false) 471 472 return resourceAwsEMRClusterRead(d, meta) 473 } 474 475 func resourceAwsEMRClusterDelete(d *schema.ResourceData, meta interface{}) error { 476 conn := meta.(*AWSClient).emrconn 477 478 req := &emr.TerminateJobFlowsInput{ 479 JobFlowIds: []*string{ 480 aws.String(d.Id()), 481 }, 482 } 483 484 _, err := conn.TerminateJobFlows(req) 485 if err != nil { 486 log.Printf("[ERROR], %s", err) 487 return err 488 } 489 490 err = resource.Retry(10*time.Minute, func() *resource.RetryError { 491 resp, err := conn.ListInstances(&emr.ListInstancesInput{ 492 ClusterId: aws.String(d.Id()), 493 }) 494 495 if err != nil { 496 return resource.NonRetryableError(err) 497 } 498 499 instanceCount := len(resp.Instances) 500 501 if resp == nil || instanceCount == 0 { 502 log.Printf("[DEBUG] No instances found for EMR Cluster (%s)", d.Id()) 503 return nil 504 } 505 506 // Collect instance status states, wait for all instances to be terminated 507 // before moving on 508 var terminated []string 509 for j, i := range resp.Instances { 510 if i.Status != nil { 511 if *i.Status.State == "TERMINATED" { 512 terminated = append(terminated, *i.Ec2InstanceId) 513 } 514 } else { 515 log.Printf("[DEBUG] Cluster instance (%d : %s) has no status", j, *i.Ec2InstanceId) 516 } 517 } 518 if len(terminated) == instanceCount { 519 log.Printf("[DEBUG] All (%d) EMR Cluster (%s) Instances terminated", instanceCount, d.Id()) 520 return nil 521 } 522 return resource.RetryableError(fmt.Errorf("[DEBUG] EMR Cluster (%s) has (%d) Instances remaining, retrying", d.Id(), len(resp.Instances))) 523 }) 524 525 if err != nil { 526 log.Printf("[ERR] Error waiting for EMR Cluster (%s) Instances to drain", d.Id()) 527 } 528 529 d.SetId("") 530 return nil 531 } 532 533 func expandApplications(apps []interface{}) []*emr.Application { 534 appOut := make([]*emr.Application, 0, len(apps)) 535 536 for _, appName := range expandStringList(apps) { 537 app := &emr.Application{ 538 Name: appName, 539 } 540 appOut = append(appOut, app) 541 } 542 return appOut 543 } 544 545 func flattenApplications(apps []*emr.Application) []interface{} { 546 appOut := make([]interface{}, 0, len(apps)) 547 548 for _, app := range apps { 549 appOut = append(appOut, *app.Name) 550 } 551 return appOut 552 } 553 554 func flattenEc2Attributes(ia *emr.Ec2InstanceAttributes) []map[string]interface{} { 555 attrs := map[string]interface{}{} 556 result := make([]map[string]interface{}, 0) 557 558 if ia.Ec2KeyName != nil { 559 attrs["key_name"] = *ia.Ec2KeyName 560 } 561 if ia.Ec2SubnetId != nil { 562 attrs["subnet_id"] = *ia.Ec2SubnetId 563 } 564 if ia.IamInstanceProfile != nil { 565 attrs["instance_profile"] = *ia.IamInstanceProfile 566 } 567 if ia.EmrManagedMasterSecurityGroup != nil { 568 attrs["emr_managed_master_security_group"] = *ia.EmrManagedMasterSecurityGroup 569 } 570 if ia.EmrManagedSlaveSecurityGroup != nil { 571 attrs["emr_managed_slave_security_group"] = *ia.EmrManagedSlaveSecurityGroup 572 } 573 574 if len(ia.AdditionalMasterSecurityGroups) > 0 { 575 strs := aws.StringValueSlice(ia.AdditionalMasterSecurityGroups) 576 attrs["additional_master_security_groups"] = strings.Join(strs, ",") 577 } 578 if len(ia.AdditionalSlaveSecurityGroups) > 0 { 579 strs := aws.StringValueSlice(ia.AdditionalSlaveSecurityGroups) 580 attrs["additional_slave_security_groups"] = strings.Join(strs, ",") 581 } 582 583 if ia.ServiceAccessSecurityGroup != nil { 584 attrs["service_access_security_group"] = *ia.ServiceAccessSecurityGroup 585 } 586 587 result = append(result, attrs) 588 589 return result 590 } 591 592 func loadGroups(d *schema.ResourceData, meta interface{}) ([]*emr.InstanceGroup, error) { 593 emrconn := meta.(*AWSClient).emrconn 594 reqGrps := &emr.ListInstanceGroupsInput{ 595 ClusterId: aws.String(d.Id()), 596 } 597 598 respGrps, errGrps := emrconn.ListInstanceGroups(reqGrps) 599 if errGrps != nil { 600 return nil, fmt.Errorf("Error reading EMR cluster: %s", errGrps) 601 } 602 return respGrps.InstanceGroups, nil 603 } 604 605 func findGroup(grps []*emr.InstanceGroup, typ string) *emr.InstanceGroup { 606 for _, grp := range grps { 607 if grp.InstanceGroupType != nil { 608 if *grp.InstanceGroupType == typ { 609 return grp 610 } 611 } 612 } 613 return nil 614 } 615 616 func expandTags(m map[string]interface{}) []*emr.Tag { 617 var result []*emr.Tag 618 for k, v := range m { 619 result = append(result, &emr.Tag{ 620 Key: aws.String(k), 621 Value: aws.String(v.(string)), 622 }) 623 } 624 625 return result 626 } 627 628 func tagsToMapEMR(ts []*emr.Tag) map[string]string { 629 result := make(map[string]string) 630 for _, t := range ts { 631 result[*t.Key] = *t.Value 632 } 633 634 return result 635 } 636 637 func diffTagsEMR(oldTags, newTags []*emr.Tag) ([]*emr.Tag, []*emr.Tag) { 638 // First, we're creating everything we have 639 create := make(map[string]interface{}) 640 for _, t := range newTags { 641 create[*t.Key] = *t.Value 642 } 643 644 // Build the list of what to remove 645 var remove []*emr.Tag 646 for _, t := range oldTags { 647 old, ok := create[*t.Key] 648 if !ok || old != *t.Value { 649 // Delete it! 650 remove = append(remove, t) 651 } 652 } 653 654 return expandTags(create), remove 655 } 656 657 func setTagsEMR(conn *emr.EMR, d *schema.ResourceData) error { 658 if d.HasChange("tags") { 659 oraw, nraw := d.GetChange("tags") 660 o := oraw.(map[string]interface{}) 661 n := nraw.(map[string]interface{}) 662 create, remove := diffTagsEMR(expandTags(o), expandTags(n)) 663 664 // Set tags 665 if len(remove) > 0 { 666 log.Printf("[DEBUG] Removing tags: %s", remove) 667 k := make([]*string, len(remove), len(remove)) 668 for i, t := range remove { 669 k[i] = t.Key 670 } 671 672 _, err := conn.RemoveTags(&emr.RemoveTagsInput{ 673 ResourceId: aws.String(d.Id()), 674 TagKeys: k, 675 }) 676 if err != nil { 677 return err 678 } 679 } 680 if len(create) > 0 { 681 log.Printf("[DEBUG] Creating tags: %s", create) 682 _, err := conn.AddTags(&emr.AddTagsInput{ 683 ResourceId: aws.String(d.Id()), 684 Tags: create, 685 }) 686 if err != nil { 687 return err 688 } 689 } 690 } 691 692 return nil 693 } 694 695 func expandBootstrapActions(bootstrapActions []interface{}) []*emr.BootstrapActionConfig { 696 actionsOut := []*emr.BootstrapActionConfig{} 697 698 for _, raw := range bootstrapActions { 699 actionAttributes := raw.(map[string]interface{}) 700 actionName := actionAttributes["name"].(string) 701 actionPath := actionAttributes["path"].(string) 702 actionArgs := actionAttributes["args"].(*schema.Set).List() 703 704 action := &emr.BootstrapActionConfig{ 705 Name: aws.String(actionName), 706 ScriptBootstrapAction: &emr.ScriptBootstrapActionConfig{ 707 Path: aws.String(actionPath), 708 Args: expandStringList(actionArgs), 709 }, 710 } 711 actionsOut = append(actionsOut, action) 712 } 713 714 return actionsOut 715 } 716 717 func expandConfigures(input string) []*emr.Configuration { 718 configsOut := []*emr.Configuration{} 719 if strings.HasPrefix(input, "http") { 720 if err := readHttpJson(input, &configsOut); err != nil { 721 log.Printf("[ERR] Error reading HTTP JSON: %s", err) 722 } 723 } else if strings.HasSuffix(input, ".json") { 724 if err := readLocalJson(input, &configsOut); err != nil { 725 log.Printf("[ERR] Error reading local JSON: %s", err) 726 } 727 } else { 728 if err := readBodyJson(input, &configsOut); err != nil { 729 log.Printf("[ERR] Error reading body JSON: %s", err) 730 } 731 } 732 log.Printf("[DEBUG] Expanded EMR Configurations %s", configsOut) 733 734 return configsOut 735 } 736 737 func readHttpJson(url string, target interface{}) error { 738 r, err := http.Get(url) 739 if err != nil { 740 return err 741 } 742 defer r.Body.Close() 743 744 return json.NewDecoder(r.Body).Decode(target) 745 } 746 747 func readLocalJson(localFile string, target interface{}) error { 748 file, e := ioutil.ReadFile(localFile) 749 if e != nil { 750 log.Printf("[ERROR] %s", e) 751 return e 752 } 753 754 return json.Unmarshal(file, target) 755 } 756 757 func readBodyJson(body string, target interface{}) error { 758 log.Printf("[DEBUG] Raw Body %s\n", body) 759 err := json.Unmarshal([]byte(body), target) 760 if err != nil { 761 log.Printf("[ERROR] parsing JSON %s", err) 762 return err 763 } 764 return nil 765 } 766 767 func resourceAwsEMRClusterStateRefreshFunc(d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc { 768 return func() (interface{}, string, error) { 769 conn := meta.(*AWSClient).emrconn 770 771 log.Printf("[INFO] Reading EMR Cluster Information: %s", d.Id()) 772 params := &emr.DescribeClusterInput{ 773 ClusterId: aws.String(d.Id()), 774 } 775 776 resp, err := conn.DescribeCluster(params) 777 778 if err != nil { 779 if awsErr, ok := err.(awserr.Error); ok { 780 if "ClusterNotFound" == awsErr.Code() { 781 return 42, "destroyed", nil 782 } 783 } 784 log.Printf("[WARN] Error on retrieving EMR Cluster (%s) when waiting: %s", d.Id(), err) 785 return nil, "", err 786 } 787 788 emrc := resp.Cluster 789 790 if emrc == nil { 791 return 42, "destroyed", nil 792 } 793 794 if resp.Cluster.Status != nil { 795 log.Printf("[DEBUG] EMR Cluster status (%s): %s", d.Id(), *resp.Cluster.Status) 796 } 797 798 return emrc, *emrc.Status.State, nil 799 } 800 }