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