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