github.com/nathanielks/terraform@v0.6.1-0.20170509030759-13e1a62319dc/builtin/providers/spotinst/resource_spotinst_aws_group.go (about)

     1  package spotinst
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/sha1"
     6  	"encoding/base64"
     7  	"encoding/hex"
     8  	"fmt"
     9  	"log"
    10  	"regexp"
    11  	"strings"
    12  
    13  	"github.com/hashicorp/terraform/helper/hashcode"
    14  	"github.com/hashicorp/terraform/helper/schema"
    15  	"github.com/spotinst/spotinst-sdk-go/spotinst"
    16  	"github.com/spotinst/spotinst-sdk-go/spotinst/util/stringutil"
    17  )
    18  
    19  func resourceSpotinstAwsGroup() *schema.Resource {
    20  	return &schema.Resource{
    21  		Create: resourceSpotinstAwsGroupCreate,
    22  		Read:   resourceSpotinstAwsGroupRead,
    23  		Update: resourceSpotinstAwsGroupUpdate,
    24  		Delete: resourceSpotinstAwsGroupDelete,
    25  
    26  		Schema: map[string]*schema.Schema{
    27  			"name": &schema.Schema{
    28  				Type:     schema.TypeString,
    29  				Required: true,
    30  			},
    31  
    32  			"description": &schema.Schema{
    33  				Type:     schema.TypeString,
    34  				Required: true,
    35  			},
    36  
    37  			"capacity": &schema.Schema{
    38  				Type:     schema.TypeSet,
    39  				Required: true,
    40  				MaxItems: 1,
    41  				Elem: &schema.Resource{
    42  					Schema: map[string]*schema.Schema{
    43  						"target": &schema.Schema{
    44  							Type:     schema.TypeInt,
    45  							Required: true,
    46  						},
    47  
    48  						"minimum": &schema.Schema{
    49  							Type:     schema.TypeInt,
    50  							Optional: true,
    51  							Computed: true,
    52  						},
    53  
    54  						"maximum": &schema.Schema{
    55  							Type:     schema.TypeInt,
    56  							Optional: true,
    57  							Computed: true,
    58  						},
    59  
    60  						"unit": &schema.Schema{
    61  							Type:     schema.TypeString,
    62  							Optional: true,
    63  							Computed: true,
    64  						},
    65  					},
    66  				},
    67  				Set: hashAwsGroupCapacity,
    68  			},
    69  
    70  			"strategy": &schema.Schema{
    71  				Type:     schema.TypeSet,
    72  				Required: true,
    73  				MaxItems: 1,
    74  				Elem: &schema.Resource{
    75  					Schema: map[string]*schema.Schema{
    76  						"risk": &schema.Schema{
    77  							Type:     schema.TypeFloat,
    78  							Optional: true,
    79  						},
    80  
    81  						"ondemand_count": &schema.Schema{
    82  							Type:     schema.TypeInt,
    83  							Optional: true,
    84  						},
    85  
    86  						"availability_vs_cost": &schema.Schema{
    87  							Type:     schema.TypeString,
    88  							Optional: true,
    89  							Computed: true,
    90  						},
    91  
    92  						"draining_timeout": &schema.Schema{
    93  							Type:     schema.TypeInt,
    94  							Optional: true,
    95  							Computed: true,
    96  						},
    97  
    98  						"utilize_reserved_instances": &schema.Schema{
    99  							Type:     schema.TypeBool,
   100  							Optional: true,
   101  							Computed: true,
   102  						},
   103  
   104  						"fallback_to_ondemand": &schema.Schema{
   105  							Type:     schema.TypeBool,
   106  							Optional: true,
   107  							Computed: true,
   108  						},
   109  					},
   110  				},
   111  				Set: hashAwsGroupStrategy,
   112  			},
   113  
   114  			"scheduled_task": &schema.Schema{
   115  				Type:     schema.TypeSet,
   116  				Optional: true,
   117  				Elem: &schema.Resource{
   118  					Schema: map[string]*schema.Schema{
   119  						"task_type": &schema.Schema{
   120  							Type:     schema.TypeString,
   121  							Optional: true,
   122  						},
   123  
   124  						"frequency": &schema.Schema{
   125  							Type:     schema.TypeString,
   126  							Optional: true,
   127  						},
   128  
   129  						"cron_expression": &schema.Schema{
   130  							Type:     schema.TypeString,
   131  							Optional: true,
   132  						},
   133  
   134  						"scale_target_capacity": &schema.Schema{
   135  							Type:     schema.TypeInt,
   136  							Optional: true,
   137  						},
   138  
   139  						"scale_min_capacity": &schema.Schema{
   140  							Type:     schema.TypeInt,
   141  							Optional: true,
   142  						},
   143  
   144  						"scale_max_capacity": &schema.Schema{
   145  							Type:     schema.TypeInt,
   146  							Optional: true,
   147  						},
   148  					},
   149  				},
   150  			},
   151  
   152  			"product": &schema.Schema{
   153  				Type:     schema.TypeString,
   154  				Required: true,
   155  				ForceNew: true,
   156  			},
   157  
   158  			"instance_types": &schema.Schema{
   159  				Type:     schema.TypeSet,
   160  				Required: true,
   161  				MaxItems: 1,
   162  				Elem: &schema.Resource{
   163  					Schema: map[string]*schema.Schema{
   164  						"ondemand": &schema.Schema{
   165  							Type:     schema.TypeString,
   166  							Required: true,
   167  						},
   168  
   169  						"spot": &schema.Schema{
   170  							Type:     schema.TypeList,
   171  							Required: true,
   172  							Elem:     &schema.Schema{Type: schema.TypeString},
   173  						},
   174  					},
   175  				},
   176  			},
   177  
   178  			"signal": &schema.Schema{
   179  				Type:     schema.TypeSet,
   180  				Optional: true,
   181  				Elem: &schema.Resource{
   182  					Schema: map[string]*schema.Schema{
   183  						"name": &schema.Schema{
   184  							Type:     schema.TypeString,
   185  							Required: true,
   186  						},
   187  					},
   188  				},
   189  			},
   190  
   191  			"availability_zone": &schema.Schema{
   192  				Type:          schema.TypeSet,
   193  				Optional:      true,
   194  				ConflictsWith: []string{"availability_zones"},
   195  				Elem: &schema.Resource{
   196  					Schema: map[string]*schema.Schema{
   197  						"name": &schema.Schema{
   198  							Type:     schema.TypeString,
   199  							Required: true,
   200  						},
   201  
   202  						"subnet_id": &schema.Schema{
   203  							Type:     schema.TypeString,
   204  							Optional: true,
   205  						},
   206  					},
   207  				},
   208  			},
   209  
   210  			"availability_zones": &schema.Schema{
   211  				Type:          schema.TypeList,
   212  				Optional:      true,
   213  				Elem:          &schema.Schema{Type: schema.TypeString},
   214  				ConflictsWith: []string{"availability_zone"},
   215  			},
   216  
   217  			"hot_ebs_volume": &schema.Schema{
   218  				Type:     schema.TypeSet,
   219  				Optional: true,
   220  				Elem: &schema.Resource{
   221  					Schema: map[string]*schema.Schema{
   222  						"device_name": &schema.Schema{
   223  							Type:     schema.TypeString,
   224  							Required: true,
   225  						},
   226  
   227  						"volume_ids": &schema.Schema{
   228  							Type:     schema.TypeList,
   229  							Required: true,
   230  							Elem:     &schema.Schema{Type: schema.TypeString},
   231  						},
   232  					},
   233  				},
   234  			},
   235  
   236  			"load_balancer": &schema.Schema{
   237  				Type:     schema.TypeSet,
   238  				Optional: true,
   239  				Elem: &schema.Resource{
   240  					Schema: map[string]*schema.Schema{
   241  						"name": &schema.Schema{
   242  							Type:     schema.TypeString,
   243  							Required: true,
   244  						},
   245  
   246  						"arn": &schema.Schema{
   247  							Type:     schema.TypeString,
   248  							Optional: true,
   249  						},
   250  
   251  						"type": &schema.Schema{
   252  							Type:     schema.TypeString,
   253  							Required: true,
   254  						},
   255  					},
   256  				},
   257  				Set: hashAwsGroupLoadBalancer,
   258  			},
   259  
   260  			"launch_specification": &schema.Schema{
   261  				Type:     schema.TypeSet,
   262  				Required: true,
   263  				MaxItems: 1,
   264  				Elem: &schema.Resource{
   265  					Schema: map[string]*schema.Schema{
   266  						"load_balancer_names": &schema.Schema{
   267  							Type:     schema.TypeList,
   268  							Optional: true,
   269  							Elem:     &schema.Schema{Type: schema.TypeString},
   270  						},
   271  
   272  						"monitoring": &schema.Schema{
   273  							Type:     schema.TypeBool,
   274  							Optional: true,
   275  							Default:  false,
   276  						},
   277  
   278  						"ebs_optimized": &schema.Schema{
   279  							Type:     schema.TypeBool,
   280  							Optional: true,
   281  							Computed: true,
   282  						},
   283  
   284  						"image_id": &schema.Schema{
   285  							Type:          schema.TypeString,
   286  							Optional:      true,
   287  							ConflictsWith: []string{"image_id"},
   288  						},
   289  
   290  						"key_pair": &schema.Schema{
   291  							Type:     schema.TypeString,
   292  							Optional: true,
   293  						},
   294  
   295  						"health_check_type": &schema.Schema{
   296  							Type:     schema.TypeString,
   297  							Optional: true,
   298  						},
   299  
   300  						"health_check_grace_period": &schema.Schema{
   301  							Type:     schema.TypeInt,
   302  							Optional: true,
   303  						},
   304  
   305  						"security_group_ids": &schema.Schema{
   306  							Type:     schema.TypeList,
   307  							Required: true,
   308  							Elem:     &schema.Schema{Type: schema.TypeString},
   309  						},
   310  
   311  						"user_data": &schema.Schema{
   312  							Type:     schema.TypeString,
   313  							Optional: true,
   314  							StateFunc: func(v interface{}) string {
   315  								switch v.(type) {
   316  								case string:
   317  									hash := sha1.Sum([]byte(v.(string)))
   318  									return hex.EncodeToString(hash[:])
   319  								default:
   320  									return ""
   321  								}
   322  							},
   323  						},
   324  
   325  						"iam_role": &schema.Schema{
   326  							Type:       schema.TypeString,
   327  							Optional:   true,
   328  							Deprecated: "Attribute iam_role is deprecated. Use iam_instance_profile instead",
   329  						},
   330  
   331  						"iam_instance_profile": &schema.Schema{
   332  							Type:     schema.TypeString,
   333  							Optional: true,
   334  						},
   335  					},
   336  				},
   337  			},
   338  
   339  			"image_id": &schema.Schema{
   340  				Type:     schema.TypeString,
   341  				Optional: true,
   342  			},
   343  
   344  			"elastic_ips": &schema.Schema{
   345  				Type:     schema.TypeList,
   346  				Optional: true,
   347  				Elem:     &schema.Schema{Type: schema.TypeString},
   348  			},
   349  
   350  			"tags": &schema.Schema{
   351  				Type:     schema.TypeMap,
   352  				Optional: true,
   353  			},
   354  
   355  			"ebs_block_device": &schema.Schema{
   356  				Type:     schema.TypeSet,
   357  				Optional: true,
   358  				Elem: &schema.Resource{
   359  					Schema: map[string]*schema.Schema{
   360  						"delete_on_termination": &schema.Schema{
   361  							Type:     schema.TypeBool,
   362  							Optional: true,
   363  							Computed: true,
   364  						},
   365  
   366  						"device_name": &schema.Schema{
   367  							Type:     schema.TypeString,
   368  							Required: true,
   369  						},
   370  
   371  						"encrypted": &schema.Schema{
   372  							Type:     schema.TypeBool,
   373  							Optional: true,
   374  							Computed: true,
   375  						},
   376  
   377  						"iops": &schema.Schema{
   378  							Type:     schema.TypeInt,
   379  							Optional: true,
   380  						},
   381  
   382  						"snapshot_id": &schema.Schema{
   383  							Type:     schema.TypeString,
   384  							Optional: true,
   385  						},
   386  
   387  						"volume_size": &schema.Schema{
   388  							Type:     schema.TypeInt,
   389  							Optional: true,
   390  						},
   391  
   392  						"volume_type": &schema.Schema{
   393  							Type:     schema.TypeString,
   394  							Optional: true,
   395  							Computed: true,
   396  						},
   397  					},
   398  				},
   399  				Set: hashAwsGroupEBSBlockDevice,
   400  			},
   401  
   402  			"ephemeral_block_device": &schema.Schema{
   403  				Type:     schema.TypeSet,
   404  				Optional: true,
   405  				Elem: &schema.Resource{
   406  					Schema: map[string]*schema.Schema{
   407  						"device_name": &schema.Schema{
   408  							Type:     schema.TypeString,
   409  							Required: true,
   410  						},
   411  
   412  						"virtual_name": &schema.Schema{
   413  							Type:     schema.TypeString,
   414  							Required: true,
   415  						},
   416  					},
   417  				},
   418  			},
   419  
   420  			"network_interface": &schema.Schema{
   421  				Type:     schema.TypeSet,
   422  				Optional: true,
   423  				Elem: &schema.Resource{
   424  					Schema: map[string]*schema.Schema{
   425  						"description": &schema.Schema{
   426  							Type:     schema.TypeString,
   427  							Required: true,
   428  						},
   429  
   430  						"device_index": &schema.Schema{
   431  							Type:     schema.TypeInt,
   432  							Required: true,
   433  						},
   434  
   435  						"secondary_private_ip_address_count": &schema.Schema{
   436  							Type:     schema.TypeInt,
   437  							Optional: true,
   438  						},
   439  
   440  						"associate_public_ip_address": &schema.Schema{
   441  							Type:     schema.TypeBool,
   442  							Optional: true,
   443  						},
   444  
   445  						"delete_on_termination": &schema.Schema{
   446  							Type:     schema.TypeBool,
   447  							Optional: true,
   448  							Computed: true,
   449  						},
   450  
   451  						"security_group_ids": &schema.Schema{
   452  							Type:     schema.TypeList,
   453  							Optional: true,
   454  							Elem:     &schema.Schema{Type: schema.TypeString},
   455  						},
   456  
   457  						"network_interface_id": &schema.Schema{
   458  							Type:     schema.TypeString,
   459  							Optional: true,
   460  						},
   461  
   462  						"private_ip_address": &schema.Schema{
   463  							Type:     schema.TypeString,
   464  							Optional: true,
   465  						},
   466  
   467  						"subnet_id": &schema.Schema{
   468  							Type:     schema.TypeString,
   469  							Optional: true,
   470  						},
   471  					},
   472  				},
   473  			},
   474  
   475  			"scaling_up_policy": scalingPolicySchema(),
   476  
   477  			"scaling_down_policy": scalingPolicySchema(),
   478  
   479  			"rancher_integration": &schema.Schema{
   480  				Type:     schema.TypeSet,
   481  				Optional: true,
   482  				MaxItems: 1,
   483  				Elem: &schema.Resource{
   484  					Schema: map[string]*schema.Schema{
   485  						"master_host": &schema.Schema{
   486  							Type:     schema.TypeString,
   487  							Required: true,
   488  						},
   489  
   490  						"access_key": &schema.Schema{
   491  							Type:     schema.TypeString,
   492  							Required: true,
   493  						},
   494  
   495  						"secret_key": &schema.Schema{
   496  							Type:     schema.TypeString,
   497  							Required: true,
   498  						},
   499  					},
   500  				},
   501  			},
   502  
   503  			"elastic_beanstalk_integration": &schema.Schema{
   504  				Type:     schema.TypeSet,
   505  				Optional: true,
   506  				MaxItems: 1,
   507  				Elem: &schema.Resource{
   508  					Schema: map[string]*schema.Schema{
   509  						"environment_id": &schema.Schema{
   510  							Type:     schema.TypeString,
   511  							Required: true,
   512  						},
   513  					},
   514  				},
   515  			},
   516  
   517  			"ec2_container_service_integration": &schema.Schema{
   518  				Type:     schema.TypeSet,
   519  				Optional: true,
   520  				MaxItems: 1,
   521  				Elem: &schema.Resource{
   522  					Schema: map[string]*schema.Schema{
   523  						"cluster_name": &schema.Schema{
   524  							Type:     schema.TypeString,
   525  							Required: true,
   526  						},
   527  					},
   528  				},
   529  			},
   530  
   531  			"kubernetes_integration": &schema.Schema{
   532  				Type:     schema.TypeSet,
   533  				Optional: true,
   534  				MaxItems: 1,
   535  				Elem: &schema.Resource{
   536  					Schema: map[string]*schema.Schema{
   537  						"api_server": &schema.Schema{
   538  							Type:     schema.TypeString,
   539  							Required: true,
   540  						},
   541  
   542  						"token": &schema.Schema{
   543  							Type:     schema.TypeString,
   544  							Required: true,
   545  						},
   546  					},
   547  				},
   548  			},
   549  
   550  			"mesosphere_integration": &schema.Schema{
   551  				Type:     schema.TypeSet,
   552  				Optional: true,
   553  				MaxItems: 1,
   554  				Elem: &schema.Resource{
   555  					Schema: map[string]*schema.Schema{
   556  						"api_server": &schema.Schema{
   557  							Type:     schema.TypeString,
   558  							Required: true,
   559  						},
   560  					},
   561  				},
   562  			},
   563  		},
   564  	}
   565  }
   566  
   567  func scalingPolicySchema() *schema.Schema {
   568  	return &schema.Schema{
   569  		Type:     schema.TypeSet,
   570  		Optional: true,
   571  		Elem: &schema.Resource{
   572  			Schema: map[string]*schema.Schema{
   573  				"policy_name": &schema.Schema{
   574  					Type:     schema.TypeString,
   575  					Required: true,
   576  				},
   577  
   578  				"metric_name": &schema.Schema{
   579  					Type:     schema.TypeString,
   580  					Required: true,
   581  				},
   582  
   583  				"statistic": &schema.Schema{
   584  					Type:     schema.TypeString,
   585  					Required: true,
   586  				},
   587  
   588  				"unit": &schema.Schema{
   589  					Type:     schema.TypeString,
   590  					Required: true,
   591  				},
   592  
   593  				"threshold": &schema.Schema{
   594  					Type:     schema.TypeFloat,
   595  					Required: true,
   596  				},
   597  
   598  				"adjustment": &schema.Schema{
   599  					Type:     schema.TypeInt,
   600  					Optional: true,
   601  				},
   602  
   603  				"min_target_capacity": &schema.Schema{
   604  					Type:     schema.TypeInt,
   605  					Optional: true,
   606  				},
   607  
   608  				"max_target_capacity": &schema.Schema{
   609  					Type:     schema.TypeInt,
   610  					Optional: true,
   611  				},
   612  
   613  				"namespace": &schema.Schema{
   614  					Type:     schema.TypeString,
   615  					Required: true,
   616  				},
   617  
   618  				"operator": &schema.Schema{
   619  					Type:     schema.TypeString,
   620  					Optional: true,
   621  					Computed: true,
   622  				},
   623  
   624  				"evaluation_periods": &schema.Schema{
   625  					Type:     schema.TypeInt,
   626  					Required: true,
   627  				},
   628  
   629  				"period": &schema.Schema{
   630  					Type:     schema.TypeInt,
   631  					Required: true,
   632  				},
   633  
   634  				"cooldown": &schema.Schema{
   635  					Type:     schema.TypeInt,
   636  					Required: true,
   637  				},
   638  
   639  				"dimensions": &schema.Schema{
   640  					Type:     schema.TypeMap,
   641  					Optional: true,
   642  				},
   643  			},
   644  		},
   645  		Set: hashAwsGroupScalingPolicy,
   646  	}
   647  }
   648  
   649  func resourceSpotinstAwsGroupCreate(d *schema.ResourceData, meta interface{}) error {
   650  	client := meta.(*spotinst.Client)
   651  	newAwsGroup, err := buildAwsGroupOpts(d, meta)
   652  	if err != nil {
   653  		return err
   654  	}
   655  	log.Printf("[DEBUG] AwsGroup create configuration: %s\n", stringutil.Stringify(newAwsGroup))
   656  	input := &spotinst.CreateAwsGroupInput{Group: newAwsGroup}
   657  	resp, err := client.AwsGroupService.Create(input)
   658  	if err != nil {
   659  		return fmt.Errorf("Error creating group: %s", err)
   660  	}
   661  	d.SetId(spotinst.StringValue(resp.Group.ID))
   662  	log.Printf("[INFO] AwsGroup created successfully: %s\n", d.Id())
   663  	return resourceSpotinstAwsGroupRead(d, meta)
   664  }
   665  
   666  func resourceSpotinstAwsGroupRead(d *schema.ResourceData, meta interface{}) error {
   667  	client := meta.(*spotinst.Client)
   668  	input := &spotinst.ReadAwsGroupInput{ID: spotinst.String(d.Id())}
   669  	resp, err := client.AwsGroupService.Read(input)
   670  	if err != nil {
   671  		return fmt.Errorf("Error retrieving group: %s", err)
   672  	}
   673  	if g := resp.Group; g != nil {
   674  		d.Set("name", g.Name)
   675  		d.Set("description", g.Description)
   676  		d.Set("product", g.Compute.Product)
   677  		d.Set("tags", tagsToMap(g.Compute.LaunchSpecification.Tags))
   678  		d.Set("elastic_ips", g.Compute.ElasticIPs)
   679  
   680  		// Set capacity.
   681  		if g.Capacity != nil {
   682  			if err := d.Set("capacity", flattenAwsGroupCapacity(g.Capacity)); err != nil {
   683  				return fmt.Errorf("Error setting capacity onfiguration: %#v", err)
   684  			}
   685  		}
   686  
   687  		// Set strategy.
   688  		if g.Strategy != nil {
   689  			if err := d.Set("strategy", flattenAwsGroupStrategy(g.Strategy)); err != nil {
   690  				return fmt.Errorf("Error setting strategy configuration: %#v", err)
   691  			}
   692  		}
   693  
   694  		// Set signals.
   695  		if g.Strategy.Signals != nil {
   696  			if err := d.Set("signal", flattenAwsGroupSignals(g.Strategy.Signals)); err != nil {
   697  				return fmt.Errorf("Error setting signals configuration: %#v", err)
   698  			}
   699  		}
   700  
   701  		// Set scaling up policies.
   702  		if g.Scaling.Up != nil {
   703  			if err := d.Set("scaling_up_policy", flattenAwsGroupScalingPolicies(g.Scaling.Up)); err != nil {
   704  				return fmt.Errorf("Error setting scaling up policies configuration: %#v", err)
   705  			}
   706  		}
   707  
   708  		// Set scaling down policies.
   709  		if g.Scaling.Down != nil {
   710  			if err := d.Set("scaling_down_policy", flattenAwsGroupScalingPolicies(g.Scaling.Down)); err != nil {
   711  				return fmt.Errorf("Error setting scaling down policies configuration: %#v", err)
   712  			}
   713  		}
   714  
   715  		// Set scheduled tasks.
   716  		if g.Scheduling.Tasks != nil {
   717  			if err := d.Set("scheduled_task", flattenAwsGroupScheduledTasks(g.Scheduling.Tasks)); err != nil {
   718  				return fmt.Errorf("Error setting scheduled tasks configuration: %#v", err)
   719  			}
   720  		}
   721  
   722  		// Set launch specification.
   723  		if g.Compute.LaunchSpecification != nil {
   724  			imageIDSetInLaunchSpec := true
   725  			if v, ok := d.GetOk("image_id"); ok && v != "" {
   726  				imageIDSetInLaunchSpec = false
   727  			}
   728  			if err := d.Set("launch_specification", flattenAwsGroupLaunchSpecification(g.Compute.LaunchSpecification, imageIDSetInLaunchSpec)); err != nil {
   729  				return fmt.Errorf("Error setting launch specification configuration: %#v", err)
   730  			}
   731  		}
   732  
   733  		// Set image ID.
   734  		if g.Compute.LaunchSpecification.ImageID != nil {
   735  			if d.Get("image_id") != nil && d.Get("image_id") != "" {
   736  				d.Set("image_id", g.Compute.LaunchSpecification.ImageID)
   737  			}
   738  		}
   739  
   740  		// Set load balancers.
   741  		if g.Compute.LaunchSpecification.LoadBalancersConfig != nil {
   742  			if err := d.Set("load_balancer", flattenAwsGroupLoadBalancers(g.Compute.LaunchSpecification.LoadBalancersConfig.LoadBalancers)); err != nil {
   743  				return fmt.Errorf("Error setting load balancers configuration: %#v", err)
   744  			}
   745  		}
   746  
   747  		// Set EBS volume pool.
   748  		if g.Compute.EBSVolumePool != nil {
   749  			if err := d.Set("hot_ebs_volume", flattenAwsGroupEBSVolumePool(g.Compute.EBSVolumePool)); err != nil {
   750  				return fmt.Errorf("Error setting EBS volume pool configuration: %#v", err)
   751  			}
   752  		}
   753  
   754  		// Set network interfaces.
   755  		if g.Compute.LaunchSpecification.NetworkInterfaces != nil {
   756  			if err := d.Set("network_interface", flattenAwsGroupNetworkInterfaces(g.Compute.LaunchSpecification.NetworkInterfaces)); err != nil {
   757  				return fmt.Errorf("Error setting network interfaces configuration: %#v", err)
   758  			}
   759  		}
   760  
   761  		// Set block devices.
   762  		if g.Compute.LaunchSpecification.BlockDevices != nil {
   763  			if err := d.Set("ebs_block_device", flattenAwsGroupEBSBlockDevices(g.Compute.LaunchSpecification.BlockDevices)); err != nil {
   764  				return fmt.Errorf("Error setting EBS block devices configuration: %#v", err)
   765  			}
   766  			if err := d.Set("ephemeral_block_device", flattenAwsGroupEphemeralBlockDevices(g.Compute.LaunchSpecification.BlockDevices)); err != nil {
   767  				return fmt.Errorf("Error setting Ephemeral block devices configuration: %#v", err)
   768  			}
   769  		}
   770  
   771  		// Set Rancher integration.
   772  		if g.Integration.Rancher != nil {
   773  			if err := d.Set("rancher_integration", flattenAwsGroupRancherIntegration(g.Integration.Rancher)); err != nil {
   774  				return fmt.Errorf("Error setting Rancher configuration: %#v", err)
   775  			}
   776  		}
   777  
   778  		// Set Elastic Beanstalk integration.
   779  		if g.Integration.ElasticBeanstalk != nil {
   780  			if err := d.Set("elastic_beanstalk_integration", flattenAwsGroupElasticBeanstalkIntegration(g.Integration.ElasticBeanstalk)); err != nil {
   781  				return fmt.Errorf("Error setting Elastic Beanstalk configuration: %#v", err)
   782  			}
   783  		}
   784  
   785  		// Set EC2 Container Service integration.
   786  		if g.Integration.EC2ContainerService != nil {
   787  			if err := d.Set("ec2_container_service_integration", flattenAwsGroupEC2ContainerServiceIntegration(g.Integration.EC2ContainerService)); err != nil {
   788  				return fmt.Errorf("Error setting EC2 Container Service configuration: %#v", err)
   789  			}
   790  		}
   791  
   792  		// Set Kubernetes integration.
   793  		if g.Integration.Kubernetes != nil {
   794  			if err := d.Set("kubernetes_integration", flattenAwsGroupKubernetesIntegration(g.Integration.Kubernetes)); err != nil {
   795  				return fmt.Errorf("Error setting Kubernetes configuration: %#v", err)
   796  			}
   797  		}
   798  
   799  		// Set Mesosphere integration.
   800  		if g.Integration.Mesosphere != nil {
   801  			if err := d.Set("mesosphere_integration", flattenAwsGroupMesosphereIntegration(g.Integration.Mesosphere)); err != nil {
   802  				return fmt.Errorf("Error setting Mesosphere configuration: %#v", err)
   803  			}
   804  		}
   805  	} else {
   806  		d.SetId("")
   807  	}
   808  	return nil
   809  }
   810  
   811  func resourceSpotinstAwsGroupUpdate(d *schema.ResourceData, meta interface{}) error {
   812  	client := meta.(*spotinst.Client)
   813  	group := &spotinst.AwsGroup{ID: spotinst.String(d.Id())}
   814  	update := false
   815  
   816  	if d.HasChange("name") {
   817  		group.Name = spotinst.String(d.Get("name").(string))
   818  		update = true
   819  	}
   820  
   821  	if d.HasChange("description") {
   822  		group.Description = spotinst.String(d.Get("description").(string))
   823  		update = true
   824  	}
   825  
   826  	if d.HasChange("capacity") {
   827  		if v, ok := d.GetOk("capacity"); ok {
   828  			if capacity, err := expandAwsGroupCapacity(v); err != nil {
   829  				return err
   830  			} else {
   831  				group.Capacity = capacity
   832  				update = true
   833  			}
   834  		}
   835  	}
   836  
   837  	if d.HasChange("strategy") {
   838  		if v, ok := d.GetOk("strategy"); ok {
   839  			if strategy, err := expandAwsGroupStrategy(v); err != nil {
   840  				return err
   841  			} else {
   842  				group.Strategy = strategy
   843  				if v, ok := d.GetOk("signal"); ok {
   844  					if signals, err := expandAwsGroupSignals(v); err != nil {
   845  						return err
   846  					} else {
   847  						group.Strategy.Signals = signals
   848  					}
   849  				}
   850  				update = true
   851  			}
   852  		}
   853  	}
   854  
   855  	if d.HasChange("launch_specification") {
   856  		if v, ok := d.GetOk("launch_specification"); ok {
   857  			lc, err := expandAwsGroupLaunchSpecification(v)
   858  			if err != nil {
   859  				return err
   860  			}
   861  			if group.Compute == nil {
   862  				group.Compute = &spotinst.AwsGroupCompute{}
   863  			}
   864  			group.Compute.LaunchSpecification = lc
   865  			update = true
   866  		}
   867  	}
   868  
   869  	if d.HasChange("image_id") {
   870  		if d.Get("image_id") != nil && d.Get("image_id") != "" {
   871  			if group.Compute == nil {
   872  				group.Compute = &spotinst.AwsGroupCompute{}
   873  			}
   874  			if group.Compute.LaunchSpecification == nil {
   875  				group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{}
   876  			}
   877  			group.Compute.LaunchSpecification.ImageID = spotinst.String(d.Get("image_id").(string))
   878  			update = true
   879  		}
   880  	}
   881  
   882  	if d.HasChange("load_balancer") {
   883  		if v, ok := d.GetOk("load_balancer"); ok {
   884  			if lbs, err := expandAwsGroupLoadBalancer(v); err != nil {
   885  				return err
   886  			} else {
   887  				if group.Compute == nil {
   888  					group.Compute = &spotinst.AwsGroupCompute{}
   889  				}
   890  				if group.Compute.LaunchSpecification == nil {
   891  					group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{}
   892  				}
   893  				if group.Compute.LaunchSpecification.LoadBalancersConfig == nil {
   894  					group.Compute.LaunchSpecification.LoadBalancersConfig = &spotinst.AwsGroupComputeLoadBalancersConfig{}
   895  					group.Compute.LaunchSpecification.LoadBalancersConfig.LoadBalancers = lbs
   896  					update = true
   897  				}
   898  			}
   899  		}
   900  	}
   901  
   902  	var blockDevicesExpanded bool
   903  
   904  	if d.HasChange("ebs_block_device") {
   905  		if v, ok := d.GetOk("ebs_block_device"); ok {
   906  			if devices, err := expandAwsGroupEBSBlockDevices(v); err != nil {
   907  				return err
   908  			} else {
   909  				if group.Compute == nil {
   910  					group.Compute = &spotinst.AwsGroupCompute{}
   911  				}
   912  				if group.Compute.LaunchSpecification == nil {
   913  					group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{}
   914  				}
   915  				if len(group.Compute.LaunchSpecification.BlockDevices) > 0 {
   916  					group.Compute.LaunchSpecification.BlockDevices = append(group.Compute.LaunchSpecification.BlockDevices, devices...)
   917  				} else {
   918  					if v, ok := d.GetOk("ephemeral_block_device"); ok {
   919  						if ephemeral, err := expandAwsGroupEphemeralBlockDevices(v); err != nil {
   920  							return err
   921  						} else {
   922  							devices = append(devices, ephemeral...)
   923  							blockDevicesExpanded = true
   924  						}
   925  					}
   926  					group.Compute.LaunchSpecification.BlockDevices = devices
   927  				}
   928  				update = true
   929  			}
   930  		}
   931  	}
   932  
   933  	if d.HasChange("ephemeral_block_device") && !blockDevicesExpanded {
   934  		if v, ok := d.GetOk("ephemeral_block_device"); ok {
   935  			if devices, err := expandAwsGroupEphemeralBlockDevices(v); err != nil {
   936  				return err
   937  			} else {
   938  				if group.Compute == nil {
   939  					group.Compute = &spotinst.AwsGroupCompute{}
   940  				}
   941  				if group.Compute.LaunchSpecification == nil {
   942  					group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{}
   943  				}
   944  				if len(group.Compute.LaunchSpecification.BlockDevices) > 0 {
   945  					group.Compute.LaunchSpecification.BlockDevices = append(group.Compute.LaunchSpecification.BlockDevices, devices...)
   946  				} else {
   947  					if v, ok := d.GetOk("ebs_block_device"); ok {
   948  						if ebs, err := expandAwsGroupEBSBlockDevices(v); err != nil {
   949  							return err
   950  						} else {
   951  							devices = append(devices, ebs...)
   952  						}
   953  					}
   954  					group.Compute.LaunchSpecification.BlockDevices = devices
   955  				}
   956  				update = true
   957  			}
   958  		}
   959  	}
   960  
   961  	if d.HasChange("network_interface") {
   962  		if v, ok := d.GetOk("network_interface"); ok {
   963  			if interfaces, err := expandAwsGroupNetworkInterfaces(v); err != nil {
   964  				return err
   965  			} else {
   966  				if group.Compute == nil {
   967  					group.Compute = &spotinst.AwsGroupCompute{}
   968  				}
   969  				if group.Compute.LaunchSpecification == nil {
   970  					group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{}
   971  				}
   972  				group.Compute.LaunchSpecification.NetworkInterfaces = interfaces
   973  				update = true
   974  			}
   975  		}
   976  	}
   977  
   978  	if d.HasChange("availability_zone") {
   979  		if v, ok := d.GetOk("availability_zone"); ok {
   980  			if zones, err := expandAwsGroupAvailabilityZones(v); err != nil {
   981  				return err
   982  			} else {
   983  				if group.Compute == nil {
   984  					group.Compute = &spotinst.AwsGroupCompute{}
   985  				}
   986  				group.Compute.AvailabilityZones = zones
   987  				update = true
   988  			}
   989  		}
   990  	}
   991  
   992  	if d.HasChange("availability_zones") {
   993  		if v, ok := d.GetOk("availability_zones"); ok {
   994  			if zones, err := expandAwsGroupAvailabilityZonesSlice(v); err != nil {
   995  				return err
   996  			} else {
   997  				if group.Compute == nil {
   998  					group.Compute = &spotinst.AwsGroupCompute{}
   999  				}
  1000  				group.Compute.AvailabilityZones = zones
  1001  				update = true
  1002  			}
  1003  		}
  1004  	}
  1005  
  1006  	if d.HasChange("hot_ebs_volume") {
  1007  		if v, ok := d.GetOk("hot_ebs_volume"); ok {
  1008  			if ebsVolumePool, err := expandAwsGroupEBSVolumePool(v); err != nil {
  1009  				return err
  1010  			} else {
  1011  				if group.Compute == nil {
  1012  					group.Compute = &spotinst.AwsGroupCompute{}
  1013  				}
  1014  				group.Compute.EBSVolumePool = ebsVolumePool
  1015  				update = true
  1016  			}
  1017  		}
  1018  	}
  1019  
  1020  	if d.HasChange("signal") {
  1021  		if v, ok := d.GetOk("signal"); ok {
  1022  			if signals, err := expandAwsGroupSignals(v); err != nil {
  1023  				return err
  1024  			} else {
  1025  				if group.Strategy == nil {
  1026  					group.Strategy = &spotinst.AwsGroupStrategy{}
  1027  				}
  1028  				group.Strategy.Signals = signals
  1029  				update = true
  1030  			}
  1031  		}
  1032  	}
  1033  
  1034  	if d.HasChange("instance_types") {
  1035  		if v, ok := d.GetOk("instance_types"); ok {
  1036  			if types, err := expandAwsGroupInstanceTypes(v); err != nil {
  1037  				return err
  1038  			} else {
  1039  				if group.Compute == nil {
  1040  					group.Compute = &spotinst.AwsGroupCompute{}
  1041  				}
  1042  				group.Compute.InstanceTypes = types
  1043  				update = true
  1044  			}
  1045  		}
  1046  	}
  1047  
  1048  	if d.HasChange("tags") {
  1049  		if v, ok := d.GetOk("tags"); ok {
  1050  			if tags, err := expandAwsGroupTags(v); err != nil {
  1051  				return err
  1052  			} else {
  1053  				if group.Compute == nil {
  1054  					group.Compute = &spotinst.AwsGroupCompute{}
  1055  				}
  1056  				if group.Compute.LaunchSpecification == nil {
  1057  					group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{}
  1058  				}
  1059  				group.Compute.LaunchSpecification.Tags = tags
  1060  				update = true
  1061  			}
  1062  		}
  1063  	}
  1064  
  1065  	if d.HasChange("elastic_ips") {
  1066  		if v, ok := d.GetOk("elastic_ips"); ok {
  1067  			if eips, err := expandAwsGroupElasticIPs(v); err != nil {
  1068  				return err
  1069  			} else {
  1070  				if group.Compute == nil {
  1071  					group.Compute = &spotinst.AwsGroupCompute{}
  1072  				}
  1073  				group.Compute.ElasticIPs = eips
  1074  				update = true
  1075  			}
  1076  		}
  1077  	}
  1078  
  1079  	if d.HasChange("scheduled_task") {
  1080  		if v, ok := d.GetOk("scheduled_task"); ok {
  1081  			if tasks, err := expandAwsGroupScheduledTasks(v); err != nil {
  1082  				return err
  1083  			} else {
  1084  				if group.Scheduling == nil {
  1085  					group.Scheduling = &spotinst.AwsGroupScheduling{}
  1086  				}
  1087  				group.Scheduling.Tasks = tasks
  1088  				update = true
  1089  			}
  1090  		}
  1091  	}
  1092  
  1093  	if d.HasChange("scaling_up_policy") {
  1094  		if v, ok := d.GetOk("scaling_up_policy"); ok {
  1095  			if policies, err := expandAwsGroupScalingPolicies(v); err != nil {
  1096  				return err
  1097  			} else {
  1098  				if group.Scaling == nil {
  1099  					group.Scaling = &spotinst.AwsGroupScaling{}
  1100  				}
  1101  				group.Scaling.Up = policies
  1102  				update = true
  1103  			}
  1104  		}
  1105  	}
  1106  
  1107  	if d.HasChange("scaling_down_policy") {
  1108  		if v, ok := d.GetOk("scaling_down_policy"); ok {
  1109  			if policies, err := expandAwsGroupScalingPolicies(v); err != nil {
  1110  				return err
  1111  			} else {
  1112  				if group.Scaling == nil {
  1113  					group.Scaling = &spotinst.AwsGroupScaling{}
  1114  				}
  1115  				group.Scaling.Down = policies
  1116  				update = true
  1117  			}
  1118  		}
  1119  	}
  1120  
  1121  	if d.HasChange("rancher_integration") {
  1122  		if v, ok := d.GetOk("rancher_integration"); ok {
  1123  			if integration, err := expandAwsGroupRancherIntegration(v); err != nil {
  1124  				return err
  1125  			} else {
  1126  				if group.Integration == nil {
  1127  					group.Integration = &spotinst.AwsGroupIntegration{}
  1128  				}
  1129  				group.Integration.Rancher = integration
  1130  				update = true
  1131  			}
  1132  		}
  1133  	}
  1134  
  1135  	if d.HasChange("elastic_eanstalk_integration") {
  1136  		if v, ok := d.GetOk("elastic_beanstalk_integration"); ok {
  1137  			if integration, err := expandAwsGroupElasticBeanstalkIntegration(v); err != nil {
  1138  				return err
  1139  			} else {
  1140  				if group.Integration == nil {
  1141  					group.Integration = &spotinst.AwsGroupIntegration{}
  1142  				}
  1143  				group.Integration.ElasticBeanstalk = integration
  1144  				update = true
  1145  			}
  1146  		}
  1147  	}
  1148  
  1149  	if d.HasChange("ec2_container_service_integration") {
  1150  		if v, ok := d.GetOk("ec2_container_service_integration"); ok {
  1151  			if integration, err := expandAwsGroupEC2ContainerServiceIntegration(v); err != nil {
  1152  				return err
  1153  			} else {
  1154  				if group.Integration == nil {
  1155  					group.Integration = &spotinst.AwsGroupIntegration{}
  1156  				}
  1157  				group.Integration.EC2ContainerService = integration
  1158  				update = true
  1159  			}
  1160  		}
  1161  	}
  1162  
  1163  	if d.HasChange("kubernetes_integration") {
  1164  		if v, ok := d.GetOk("kubernetes_integration"); ok {
  1165  			if integration, err := expandAwsGroupKubernetesIntegration(v); err != nil {
  1166  				return err
  1167  			} else {
  1168  				if group.Integration == nil {
  1169  					group.Integration = &spotinst.AwsGroupIntegration{}
  1170  				}
  1171  				group.Integration.Kubernetes = integration
  1172  				update = true
  1173  			}
  1174  		}
  1175  	}
  1176  
  1177  	if d.HasChange("mesosphere_integration") {
  1178  		if v, ok := d.GetOk("mesosphere_integration"); ok {
  1179  			if integration, err := expandAwsGroupMesosphereIntegration(v); err != nil {
  1180  				return err
  1181  			} else {
  1182  				if group.Integration == nil {
  1183  					group.Integration = &spotinst.AwsGroupIntegration{}
  1184  				}
  1185  				group.Integration.Mesosphere = integration
  1186  				update = true
  1187  			}
  1188  		}
  1189  	}
  1190  
  1191  	if update {
  1192  		log.Printf("[DEBUG] AwsGroup update configuration: %s\n", stringutil.Stringify(group))
  1193  		input := &spotinst.UpdateAwsGroupInput{Group: group}
  1194  		if _, err := client.AwsGroupService.Update(input); err != nil {
  1195  			return fmt.Errorf("Error updating group %s: %s", d.Id(), err)
  1196  		}
  1197  	}
  1198  
  1199  	return resourceSpotinstAwsGroupRead(d, meta)
  1200  }
  1201  
  1202  func resourceSpotinstAwsGroupDelete(d *schema.ResourceData, meta interface{}) error {
  1203  	client := meta.(*spotinst.Client)
  1204  	log.Printf("[INFO] Deleting group: %s\n", d.Id())
  1205  	input := &spotinst.DeleteAwsGroupInput{ID: spotinst.String(d.Id())}
  1206  	if _, err := client.AwsGroupService.Delete(input); err != nil {
  1207  		return fmt.Errorf("Error deleting group: %s", err)
  1208  	}
  1209  	d.SetId("")
  1210  	return nil
  1211  }
  1212  
  1213  func flattenAwsGroupCapacity(capacity *spotinst.AwsGroupCapacity) []interface{} {
  1214  	result := make(map[string]interface{})
  1215  	result["target"] = spotinst.IntValue(capacity.Target)
  1216  	result["minimum"] = spotinst.IntValue(capacity.Minimum)
  1217  	result["maximum"] = spotinst.IntValue(capacity.Maximum)
  1218  	result["unit"] = spotinst.StringValue(capacity.Unit)
  1219  	return []interface{}{result}
  1220  }
  1221  
  1222  func flattenAwsGroupStrategy(strategy *spotinst.AwsGroupStrategy) []interface{} {
  1223  	result := make(map[string]interface{})
  1224  	result["risk"] = spotinst.Float64Value(strategy.Risk)
  1225  	result["ondemand_count"] = spotinst.IntValue(strategy.OnDemandCount)
  1226  	result["availability_vs_cost"] = spotinst.StringValue(strategy.AvailabilityVsCost)
  1227  	result["draining_timeout"] = spotinst.IntValue(strategy.DrainingTimeout)
  1228  	result["utilize_reserved_instances"] = spotinst.BoolValue(strategy.UtilizeReservedInstances)
  1229  	result["fallback_to_ondemand"] = spotinst.BoolValue(strategy.FallbackToOnDemand)
  1230  	return []interface{}{result}
  1231  }
  1232  
  1233  func flattenAwsGroupLaunchSpecification(lspec *spotinst.AwsGroupComputeLaunchSpecification, includeImageID bool) []interface{} {
  1234  	result := make(map[string]interface{})
  1235  	result["health_check_grace_period"] = spotinst.IntValue(lspec.HealthCheckGracePeriod)
  1236  	result["health_check_type"] = spotinst.StringValue(lspec.HealthCheckType)
  1237  	if includeImageID {
  1238  		result["image_id"] = spotinst.StringValue(lspec.ImageID)
  1239  	}
  1240  	result["key_pair"] = spotinst.StringValue(lspec.KeyPair)
  1241  	if lspec.UserData != nil && spotinst.StringValue(lspec.UserData) != "" {
  1242  		decodedUserData, _ := base64.StdEncoding.DecodeString(spotinst.StringValue(lspec.UserData))
  1243  		result["user_data"] = string(decodedUserData)
  1244  	} else {
  1245  		result["user_data"] = ""
  1246  	}
  1247  	result["monitoring"] = spotinst.BoolValue(lspec.Monitoring)
  1248  	result["ebs_optimized"] = spotinst.BoolValue(lspec.EBSOptimized)
  1249  	result["load_balancer_names"] = lspec.LoadBalancerNames
  1250  	result["security_group_ids"] = lspec.SecurityGroupIDs
  1251  	if lspec.IamInstanceProfile != nil {
  1252  		if lspec.IamInstanceProfile.Arn != nil {
  1253  			result["iam_instance_profile"] = spotinst.StringValue(lspec.IamInstanceProfile.Arn)
  1254  		} else {
  1255  			result["iam_instance_profile"] = spotinst.StringValue(lspec.IamInstanceProfile.Name)
  1256  		}
  1257  	}
  1258  	return []interface{}{result}
  1259  }
  1260  
  1261  func flattenAwsGroupLoadBalancers(balancers []*spotinst.AwsGroupComputeLoadBalancer) []interface{} {
  1262  	result := make([]interface{}, 0, len(balancers))
  1263  	for _, b := range balancers {
  1264  		m := make(map[string]interface{})
  1265  		m["name"] = spotinst.StringValue(b.Name)
  1266  		m["arn"] = spotinst.StringValue(b.Arn)
  1267  		m["type"] = strings.ToLower(spotinst.StringValue(b.Type))
  1268  		result = append(result, m)
  1269  	}
  1270  	return result
  1271  }
  1272  
  1273  func flattenAwsGroupEBSVolumePool(volumes []*spotinst.AwsGroupComputeEBSVolume) []interface{} {
  1274  	result := make([]interface{}, 0, len(volumes))
  1275  	for _, v := range volumes {
  1276  		m := make(map[string]interface{})
  1277  		m["device_name"] = spotinst.StringValue(v.DeviceName)
  1278  		m["volume_ids"] = v.VolumeIDs
  1279  		result = append(result, m)
  1280  	}
  1281  	return result
  1282  }
  1283  
  1284  func flattenAwsGroupSignals(signals []*spotinst.AwsGroupStrategySignal) []interface{} {
  1285  	result := make([]interface{}, 0, len(signals))
  1286  	for _, s := range signals {
  1287  		m := make(map[string]interface{})
  1288  		m["name"] = strings.ToLower(spotinst.StringValue(s.Name))
  1289  		result = append(result, m)
  1290  	}
  1291  	return result
  1292  }
  1293  
  1294  func flattenAwsGroupScheduledTasks(tasks []*spotinst.AwsGroupScheduledTask) []interface{} {
  1295  	result := make([]interface{}, 0, len(tasks))
  1296  	for _, t := range tasks {
  1297  		m := make(map[string]interface{})
  1298  		m["task_type"] = spotinst.StringValue(t.TaskType)
  1299  		m["cron_expression"] = spotinst.StringValue(t.CronExpression)
  1300  		m["frequency"] = spotinst.StringValue(t.Frequency)
  1301  		m["scale_target_capacity"] = spotinst.IntValue(t.ScaleTargetCapacity)
  1302  		m["scale_min_capacity"] = spotinst.IntValue(t.ScaleMinCapacity)
  1303  		m["scale_max_capacity"] = spotinst.IntValue(t.ScaleMaxCapacity)
  1304  		result = append(result, m)
  1305  	}
  1306  	return result
  1307  }
  1308  
  1309  func flattenAwsGroupScalingPolicies(policies []*spotinst.AwsGroupScalingPolicy) []interface{} {
  1310  	result := make([]interface{}, 0, len(policies))
  1311  	for _, p := range policies {
  1312  		m := make(map[string]interface{})
  1313  		m["adjustment"] = spotinst.IntValue(p.Adjustment)
  1314  		m["cooldown"] = spotinst.IntValue(p.Cooldown)
  1315  		m["evaluation_periods"] = spotinst.IntValue(p.EvaluationPeriods)
  1316  		m["min_target_capacity"] = spotinst.IntValue(p.MinTargetCapacity)
  1317  		m["max_target_capacity"] = spotinst.IntValue(p.MaxTargetCapacity)
  1318  		m["metric_name"] = spotinst.StringValue(p.MetricName)
  1319  		m["namespace"] = spotinst.StringValue(p.Namespace)
  1320  		m["operator"] = spotinst.StringValue(p.Operator)
  1321  		m["period"] = spotinst.IntValue(p.Period)
  1322  		m["policy_name"] = spotinst.StringValue(p.PolicyName)
  1323  		m["statistic"] = spotinst.StringValue(p.Statistic)
  1324  		m["threshold"] = spotinst.Float64Value(p.Threshold)
  1325  		m["unit"] = spotinst.StringValue(p.Unit)
  1326  		if len(p.Dimensions) > 0 {
  1327  			flatDims := make(map[string]interface{})
  1328  			for _, d := range p.Dimensions {
  1329  				flatDims[spotinst.StringValue(d.Name)] = *d.Value
  1330  			}
  1331  			m["dimensions"] = flatDims
  1332  		}
  1333  		result = append(result, m)
  1334  	}
  1335  	return result
  1336  }
  1337  
  1338  func flattenAwsGroupNetworkInterfaces(ifaces []*spotinst.AwsGroupComputeNetworkInterface) []interface{} {
  1339  	result := make([]interface{}, 0, len(ifaces))
  1340  	for _, iface := range ifaces {
  1341  		m := make(map[string]interface{})
  1342  		m["associate_public_ip_address"] = spotinst.BoolValue(iface.AssociatePublicIPAddress)
  1343  		m["delete_on_termination"] = spotinst.BoolValue(iface.DeleteOnTermination)
  1344  		m["description"] = spotinst.StringValue(iface.Description)
  1345  		m["device_index"] = spotinst.IntValue(iface.DeviceIndex)
  1346  		m["network_interface_id"] = spotinst.StringValue(iface.ID)
  1347  		m["private_ip_address"] = spotinst.StringValue(iface.PrivateIPAddress)
  1348  		m["secondary_private_ip_address_count"] = spotinst.IntValue(iface.SecondaryPrivateIPAddressCount)
  1349  		m["subnet_id"] = spotinst.StringValue(iface.SubnetID)
  1350  		m["security_group_ids"] = iface.SecurityGroupsIDs
  1351  		result = append(result, m)
  1352  	}
  1353  	return result
  1354  }
  1355  
  1356  func flattenAwsGroupEBSBlockDevices(devices []*spotinst.AwsGroupComputeBlockDevice) []interface{} {
  1357  	result := make([]interface{}, 0, len(devices))
  1358  	for _, dev := range devices {
  1359  		if dev.EBS != nil {
  1360  			m := make(map[string]interface{})
  1361  			m["device_name"] = spotinst.StringValue(dev.DeviceName)
  1362  			m["delete_on_termination"] = spotinst.BoolValue(dev.EBS.DeleteOnTermination)
  1363  			m["encrypted"] = spotinst.BoolValue(dev.EBS.Encrypted)
  1364  			m["iops"] = spotinst.IntValue(dev.EBS.IOPS)
  1365  			m["snapshot_id"] = spotinst.StringValue(dev.EBS.SnapshotID)
  1366  			m["volume_type"] = spotinst.StringValue(dev.EBS.VolumeType)
  1367  			m["volume_size"] = spotinst.IntValue(dev.EBS.VolumeSize)
  1368  			result = append(result, m)
  1369  		}
  1370  	}
  1371  	return result
  1372  }
  1373  
  1374  func flattenAwsGroupEphemeralBlockDevices(devices []*spotinst.AwsGroupComputeBlockDevice) []interface{} {
  1375  	result := make([]interface{}, 0, len(devices))
  1376  	for _, dev := range devices {
  1377  		if dev.EBS == nil {
  1378  			m := make(map[string]interface{})
  1379  			m["device_name"] = spotinst.StringValue(dev.DeviceName)
  1380  			m["virtual_name"] = spotinst.StringValue(dev.VirtualName)
  1381  			result = append(result, m)
  1382  		}
  1383  	}
  1384  	return result
  1385  }
  1386  
  1387  func flattenAwsGroupRancherIntegration(integration *spotinst.AwsGroupRancherIntegration) []interface{} {
  1388  	result := make(map[string]interface{})
  1389  	result["master_host"] = spotinst.StringValue(integration.MasterHost)
  1390  	result["access_key"] = spotinst.StringValue(integration.AccessKey)
  1391  	result["secret_key"] = spotinst.StringValue(integration.SecretKey)
  1392  	return []interface{}{result}
  1393  }
  1394  
  1395  func flattenAwsGroupElasticBeanstalkIntegration(integration *spotinst.AwsGroupElasticBeanstalkIntegration) []interface{} {
  1396  	result := make(map[string]interface{})
  1397  	result["environment_id"] = spotinst.StringValue(integration.EnvironmentID)
  1398  	return []interface{}{result}
  1399  }
  1400  
  1401  func flattenAwsGroupEC2ContainerServiceIntegration(integration *spotinst.AwsGroupEC2ContainerServiceIntegration) []interface{} {
  1402  	result := make(map[string]interface{})
  1403  	result["cluster_name"] = spotinst.StringValue(integration.ClusterName)
  1404  	return []interface{}{result}
  1405  }
  1406  
  1407  func flattenAwsGroupKubernetesIntegration(integration *spotinst.AwsGroupKubernetesIntegration) []interface{} {
  1408  	result := make(map[string]interface{})
  1409  	result["api_server"] = spotinst.StringValue(integration.Server)
  1410  	result["token"] = spotinst.StringValue(integration.Token)
  1411  	return []interface{}{result}
  1412  }
  1413  
  1414  func flattenAwsGroupMesosphereIntegration(integration *spotinst.AwsGroupMesosphereIntegration) []interface{} {
  1415  	result := make(map[string]interface{})
  1416  	result["api_server"] = spotinst.StringValue(integration.Server)
  1417  	return []interface{}{result}
  1418  }
  1419  
  1420  // buildAwsGroupOpts builds the Spotinst AWS Group options.
  1421  func buildAwsGroupOpts(d *schema.ResourceData, meta interface{}) (*spotinst.AwsGroup, error) {
  1422  	group := &spotinst.AwsGroup{
  1423  		Name:        spotinst.String(d.Get("name").(string)),
  1424  		Description: spotinst.String(d.Get("description").(string)),
  1425  		Scaling:     &spotinst.AwsGroupScaling{},
  1426  		Scheduling:  &spotinst.AwsGroupScheduling{},
  1427  		Integration: &spotinst.AwsGroupIntegration{},
  1428  		Compute: &spotinst.AwsGroupCompute{
  1429  			Product:             spotinst.String(d.Get("product").(string)),
  1430  			LaunchSpecification: &spotinst.AwsGroupComputeLaunchSpecification{},
  1431  		},
  1432  	}
  1433  
  1434  	if v, ok := d.GetOk("capacity"); ok {
  1435  		if capacity, err := expandAwsGroupCapacity(v); err != nil {
  1436  			return nil, err
  1437  		} else {
  1438  			group.Capacity = capacity
  1439  		}
  1440  	}
  1441  
  1442  	if v, ok := d.GetOk("strategy"); ok {
  1443  		if strategy, err := expandAwsGroupStrategy(v); err != nil {
  1444  			return nil, err
  1445  		} else {
  1446  			group.Strategy = strategy
  1447  		}
  1448  	}
  1449  
  1450  	if v, ok := d.GetOk("scaling_up_policy"); ok {
  1451  		if policies, err := expandAwsGroupScalingPolicies(v); err != nil {
  1452  			return nil, err
  1453  		} else {
  1454  			group.Scaling.Up = policies
  1455  		}
  1456  	}
  1457  
  1458  	if v, ok := d.GetOk("scaling_down_policy"); ok {
  1459  		if policies, err := expandAwsGroupScalingPolicies(v); err != nil {
  1460  			return nil, err
  1461  		} else {
  1462  			group.Scaling.Down = policies
  1463  		}
  1464  	}
  1465  
  1466  	if v, ok := d.GetOk("scheduled_task"); ok {
  1467  		if tasks, err := expandAwsGroupScheduledTasks(v); err != nil {
  1468  			return nil, err
  1469  		} else {
  1470  			group.Scheduling.Tasks = tasks
  1471  		}
  1472  	}
  1473  
  1474  	if v, ok := d.GetOk("instance_types"); ok {
  1475  		if types, err := expandAwsGroupInstanceTypes(v); err != nil {
  1476  			return nil, err
  1477  		} else {
  1478  			group.Compute.InstanceTypes = types
  1479  		}
  1480  	}
  1481  
  1482  	if v, ok := d.GetOk("elastic_ips"); ok {
  1483  		if eips, err := expandAwsGroupElasticIPs(v); err != nil {
  1484  			return nil, err
  1485  		} else {
  1486  			group.Compute.ElasticIPs = eips
  1487  		}
  1488  	}
  1489  
  1490  	if v, ok := d.GetOk("availability_zone"); ok {
  1491  		if zones, err := expandAwsGroupAvailabilityZones(v); err != nil {
  1492  			return nil, err
  1493  		} else {
  1494  			group.Compute.AvailabilityZones = zones
  1495  		}
  1496  	}
  1497  
  1498  	if v, ok := d.GetOk("availability_zones"); ok {
  1499  		if zones, err := expandAwsGroupAvailabilityZonesSlice(v); err != nil {
  1500  			return nil, err
  1501  		} else {
  1502  			group.Compute.AvailabilityZones = zones
  1503  		}
  1504  	}
  1505  
  1506  	if v, ok := d.GetOk("hot_ebs_volume"); ok {
  1507  		if ebsVolumePool, err := expandAwsGroupEBSVolumePool(v); err != nil {
  1508  			return nil, err
  1509  		} else {
  1510  			group.Compute.EBSVolumePool = ebsVolumePool
  1511  		}
  1512  	}
  1513  
  1514  	if v, ok := d.GetOk("signal"); ok {
  1515  		if signals, err := expandAwsGroupSignals(v); err != nil {
  1516  			return nil, err
  1517  		} else {
  1518  			group.Strategy.Signals = signals
  1519  		}
  1520  	}
  1521  
  1522  	if v, ok := d.GetOk("launch_specification"); ok {
  1523  		if lc, err := expandAwsGroupLaunchSpecification(v); err != nil {
  1524  			return nil, err
  1525  		} else {
  1526  			group.Compute.LaunchSpecification = lc
  1527  		}
  1528  	}
  1529  
  1530  	if v, ok := d.GetOk("image_id"); ok {
  1531  		group.Compute.LaunchSpecification.ImageID = spotinst.String(v.(string))
  1532  	}
  1533  
  1534  	if v, ok := d.GetOk("load_balancer"); ok {
  1535  		if lbs, err := expandAwsGroupLoadBalancer(v); err != nil {
  1536  			return nil, err
  1537  		} else {
  1538  			if group.Compute.LaunchSpecification.LoadBalancersConfig == nil {
  1539  				group.Compute.LaunchSpecification.LoadBalancersConfig = &spotinst.AwsGroupComputeLoadBalancersConfig{}
  1540  			}
  1541  			group.Compute.LaunchSpecification.LoadBalancersConfig.LoadBalancers = lbs
  1542  		}
  1543  	}
  1544  
  1545  	if v, ok := d.GetOk("tags"); ok {
  1546  		if tags, err := expandAwsGroupTags(v); err != nil {
  1547  			return nil, err
  1548  		} else {
  1549  			group.Compute.LaunchSpecification.Tags = tags
  1550  		}
  1551  	}
  1552  
  1553  	if v, ok := d.GetOk("network_interface"); ok {
  1554  		if interfaces, err := expandAwsGroupNetworkInterfaces(v); err != nil {
  1555  			return nil, err
  1556  		} else {
  1557  			group.Compute.LaunchSpecification.NetworkInterfaces = interfaces
  1558  		}
  1559  	}
  1560  
  1561  	if v, ok := d.GetOk("ebs_block_device"); ok {
  1562  		if devices, err := expandAwsGroupEBSBlockDevices(v); err != nil {
  1563  			return nil, err
  1564  		} else {
  1565  			group.Compute.LaunchSpecification.BlockDevices = devices
  1566  		}
  1567  	}
  1568  
  1569  	if v, ok := d.GetOk("ephemeral_block_device"); ok {
  1570  		if devices, err := expandAwsGroupEphemeralBlockDevices(v); err != nil {
  1571  			return nil, err
  1572  		} else {
  1573  			if len(group.Compute.LaunchSpecification.BlockDevices) > 0 {
  1574  				group.Compute.LaunchSpecification.BlockDevices = append(group.Compute.LaunchSpecification.BlockDevices, devices...)
  1575  			} else {
  1576  				group.Compute.LaunchSpecification.BlockDevices = devices
  1577  			}
  1578  		}
  1579  	}
  1580  
  1581  	if v, ok := d.GetOk("rancher_integration"); ok {
  1582  		if integration, err := expandAwsGroupRancherIntegration(v); err != nil {
  1583  			return nil, err
  1584  		} else {
  1585  			group.Integration.Rancher = integration
  1586  		}
  1587  	}
  1588  
  1589  	if v, ok := d.GetOk("elastic_beanstalk_integration"); ok {
  1590  		if integration, err := expandAwsGroupElasticBeanstalkIntegration(v); err != nil {
  1591  			return nil, err
  1592  		} else {
  1593  			group.Integration.ElasticBeanstalk = integration
  1594  		}
  1595  	}
  1596  
  1597  	if v, ok := d.GetOk("ec2_container_service_integration"); ok {
  1598  		if integration, err := expandAwsGroupEC2ContainerServiceIntegration(v); err != nil {
  1599  			return nil, err
  1600  		} else {
  1601  			group.Integration.EC2ContainerService = integration
  1602  		}
  1603  	}
  1604  
  1605  	if v, ok := d.GetOk("kubernetes_integration"); ok {
  1606  		if integration, err := expandAwsGroupKubernetesIntegration(v); err != nil {
  1607  			return nil, err
  1608  		} else {
  1609  			group.Integration.Kubernetes = integration
  1610  		}
  1611  	}
  1612  
  1613  	return group, nil
  1614  }
  1615  
  1616  // expandAwsGroupCapacity expands the Capacity block.
  1617  func expandAwsGroupCapacity(data interface{}) (*spotinst.AwsGroupCapacity, error) {
  1618  	list := data.(*schema.Set).List()
  1619  	m := list[0].(map[string]interface{})
  1620  	capacity := &spotinst.AwsGroupCapacity{}
  1621  
  1622  	if v, ok := m["minimum"].(int); ok && v >= 0 {
  1623  		capacity.Minimum = spotinst.Int(v)
  1624  	}
  1625  
  1626  	if v, ok := m["maximum"].(int); ok && v >= 0 {
  1627  		capacity.Maximum = spotinst.Int(v)
  1628  	}
  1629  
  1630  	if v, ok := m["target"].(int); ok && v >= 0 {
  1631  		capacity.Target = spotinst.Int(v)
  1632  	}
  1633  
  1634  	if v, ok := m["unit"].(string); ok && v != "" {
  1635  		capacity.Unit = spotinst.String(v)
  1636  	}
  1637  
  1638  	log.Printf("[DEBUG] AwsGroup capacity configuration: %s\n", stringutil.Stringify(capacity))
  1639  	return capacity, nil
  1640  }
  1641  
  1642  // expandAwsGroupStrategy expands the Strategy block.
  1643  func expandAwsGroupStrategy(data interface{}) (*spotinst.AwsGroupStrategy, error) {
  1644  	list := data.(*schema.Set).List()
  1645  	m := list[0].(map[string]interface{})
  1646  	strategy := &spotinst.AwsGroupStrategy{}
  1647  
  1648  	if v, ok := m["risk"].(float64); ok && v >= 0 {
  1649  		strategy.Risk = spotinst.Float64(v)
  1650  	}
  1651  
  1652  	if v, ok := m["ondemand_count"].(int); ok && v >= 0 && spotinst.Float64Value(strategy.Risk) == 0 {
  1653  		strategy.OnDemandCount = spotinst.Int(v)
  1654  		strategy.Risk = nil
  1655  	}
  1656  
  1657  	if v, ok := m["availability_vs_cost"].(string); ok && v != "" {
  1658  		strategy.AvailabilityVsCost = spotinst.String(v)
  1659  	}
  1660  
  1661  	if v, ok := m["draining_timeout"].(int); ok && v > 0 {
  1662  		strategy.DrainingTimeout = spotinst.Int(v)
  1663  	}
  1664  
  1665  	if v, ok := m["utilize_reserved_instances"].(bool); ok {
  1666  		strategy.UtilizeReservedInstances = spotinst.Bool(v)
  1667  	}
  1668  
  1669  	if v, ok := m["fallback_to_ondemand"].(bool); ok {
  1670  		strategy.FallbackToOnDemand = spotinst.Bool(v)
  1671  	}
  1672  
  1673  	log.Printf("[DEBUG] AwsGroup strategy configuration: %s\n", stringutil.Stringify(strategy))
  1674  	return strategy, nil
  1675  }
  1676  
  1677  // expandAwsGroupScalingPolicies expands the Scaling Policy block.
  1678  func expandAwsGroupScalingPolicies(data interface{}) ([]*spotinst.AwsGroupScalingPolicy, error) {
  1679  	list := data.(*schema.Set).List()
  1680  	policies := make([]*spotinst.AwsGroupScalingPolicy, 0, len(list))
  1681  	for _, item := range list {
  1682  		m := item.(map[string]interface{})
  1683  		policy := &spotinst.AwsGroupScalingPolicy{}
  1684  
  1685  		if v, ok := m["policy_name"].(string); ok && v != "" {
  1686  			policy.PolicyName = spotinst.String(v)
  1687  		}
  1688  
  1689  		if v, ok := m["metric_name"].(string); ok && v != "" {
  1690  			policy.MetricName = spotinst.String(v)
  1691  		}
  1692  
  1693  		if v, ok := m["statistic"].(string); ok && v != "" {
  1694  			policy.Statistic = spotinst.String(v)
  1695  		}
  1696  
  1697  		if v, ok := m["unit"].(string); ok && v != "" {
  1698  			policy.Unit = spotinst.String(v)
  1699  		}
  1700  
  1701  		if v, ok := m["threshold"].(float64); ok && v > 0 {
  1702  			policy.Threshold = spotinst.Float64(v)
  1703  		}
  1704  
  1705  		if v, ok := m["adjustment"].(int); ok && v > 0 {
  1706  			policy.Adjustment = spotinst.Int(v)
  1707  		}
  1708  
  1709  		if v, ok := m["min_target_capacity"].(int); ok && v > 0 {
  1710  			policy.MinTargetCapacity = spotinst.Int(v)
  1711  		}
  1712  
  1713  		if v, ok := m["max_target_capacity"].(int); ok && v > 0 {
  1714  			policy.MaxTargetCapacity = spotinst.Int(v)
  1715  		}
  1716  
  1717  		if v, ok := m["namespace"].(string); ok && v != "" {
  1718  			policy.Namespace = spotinst.String(v)
  1719  		}
  1720  
  1721  		if v, ok := m["operator"].(string); ok && v != "" {
  1722  			policy.Operator = spotinst.String(v)
  1723  		}
  1724  
  1725  		if v, ok := m["period"].(int); ok && v > 0 {
  1726  			policy.Period = spotinst.Int(v)
  1727  		}
  1728  
  1729  		if v, ok := m["evaluation_periods"].(int); ok && v > 0 {
  1730  			policy.EvaluationPeriods = spotinst.Int(v)
  1731  		}
  1732  
  1733  		if v, ok := m["cooldown"].(int); ok && v > 0 {
  1734  			policy.Cooldown = spotinst.Int(v)
  1735  		}
  1736  
  1737  		if v, ok := m["dimensions"]; ok {
  1738  			dimensions := expandAwsGroupScalingPolicyDimensions(v.(map[string]interface{}))
  1739  			policy.Dimensions = dimensions
  1740  		}
  1741  
  1742  		if v, ok := m["namespace"].(string); ok && v != "" {
  1743  			log.Printf("[DEBUG] AwsGroup scaling policy configuration: %s\n", stringutil.Stringify(policy))
  1744  			policies = append(policies, policy)
  1745  		}
  1746  	}
  1747  
  1748  	return policies, nil
  1749  }
  1750  
  1751  func expandAwsGroupScalingPolicyDimensions(list map[string]interface{}) []*spotinst.AwsGroupScalingPolicyDimension {
  1752  	dimensions := make([]*spotinst.AwsGroupScalingPolicyDimension, 0, len(list))
  1753  	for name, val := range list {
  1754  		dimension := &spotinst.AwsGroupScalingPolicyDimension{
  1755  			Name:  spotinst.String(name),
  1756  			Value: spotinst.String(val.(string)),
  1757  		}
  1758  		log.Printf("[DEBUG] AwsGroup scaling policy dimension: %s\n", stringutil.Stringify(dimension))
  1759  		dimensions = append(dimensions, dimension)
  1760  	}
  1761  	return dimensions
  1762  }
  1763  
  1764  // expandAwsGroupScheduledTasks expands the Scheduled Task block.
  1765  func expandAwsGroupScheduledTasks(data interface{}) ([]*spotinst.AwsGroupScheduledTask, error) {
  1766  	list := data.(*schema.Set).List()
  1767  	tasks := make([]*spotinst.AwsGroupScheduledTask, 0, len(list))
  1768  	for _, item := range list {
  1769  		m := item.(map[string]interface{})
  1770  		task := &spotinst.AwsGroupScheduledTask{}
  1771  
  1772  		if v, ok := m["task_type"].(string); ok && v != "" {
  1773  			task.TaskType = spotinst.String(v)
  1774  		}
  1775  
  1776  		if v, ok := m["frequency"].(string); ok && v != "" {
  1777  			task.Frequency = spotinst.String(v)
  1778  		}
  1779  
  1780  		if v, ok := m["cron_expression"].(string); ok && v != "" {
  1781  			task.CronExpression = spotinst.String(v)
  1782  		}
  1783  
  1784  		if v, ok := m["scale_target_capacity"].(int); ok && v > 0 {
  1785  			task.ScaleTargetCapacity = spotinst.Int(v)
  1786  		}
  1787  
  1788  		if v, ok := m["scale_min_capacity"].(int); ok && v > 0 {
  1789  			task.ScaleMinCapacity = spotinst.Int(v)
  1790  		}
  1791  
  1792  		if v, ok := m["scale_max_capacity"].(int); ok && v > 0 {
  1793  			task.ScaleMaxCapacity = spotinst.Int(v)
  1794  		}
  1795  
  1796  		log.Printf("[DEBUG] AwsGroup scheduled task configuration: %s\n", stringutil.Stringify(task))
  1797  		tasks = append(tasks, task)
  1798  	}
  1799  
  1800  	return tasks, nil
  1801  }
  1802  
  1803  // expandAwsGroupAvailabilityZones expands the Availability Zone block.
  1804  func expandAwsGroupAvailabilityZones(data interface{}) ([]*spotinst.AwsGroupComputeAvailabilityZone, error) {
  1805  	list := data.(*schema.Set).List()
  1806  	zones := make([]*spotinst.AwsGroupComputeAvailabilityZone, 0, len(list))
  1807  	for _, item := range list {
  1808  		m := item.(map[string]interface{})
  1809  		zone := &spotinst.AwsGroupComputeAvailabilityZone{}
  1810  
  1811  		if v, ok := m["name"].(string); ok && v != "" {
  1812  			zone.Name = spotinst.String(v)
  1813  		}
  1814  
  1815  		if v, ok := m["subnet_id"].(string); ok && v != "" {
  1816  			zone.SubnetID = spotinst.String(v)
  1817  		}
  1818  
  1819  		log.Printf("[DEBUG] AwsGroup availability zone configuration: %s\n", stringutil.Stringify(zone))
  1820  		zones = append(zones, zone)
  1821  	}
  1822  
  1823  	return zones, nil
  1824  }
  1825  
  1826  // expandAwsGroupAvailabilityZonesSlice expands the Availability Zone block when provided as a slice.
  1827  func expandAwsGroupAvailabilityZonesSlice(data interface{}) ([]*spotinst.AwsGroupComputeAvailabilityZone, error) {
  1828  	list := data.([]interface{})
  1829  	zones := make([]*spotinst.AwsGroupComputeAvailabilityZone, 0, len(list))
  1830  	for _, str := range list {
  1831  		if s, ok := str.(string); ok {
  1832  			parts := strings.Split(s, ":")
  1833  			zone := &spotinst.AwsGroupComputeAvailabilityZone{}
  1834  			if len(parts) >= 1 && parts[0] != "" {
  1835  				zone.Name = spotinst.String(parts[0])
  1836  			}
  1837  			if len(parts) == 2 && parts[1] != "" {
  1838  				zone.SubnetID = spotinst.String(parts[1])
  1839  			}
  1840  			log.Printf("[DEBUG] AwsGroup availability zone configuration: %s\n", stringutil.Stringify(zone))
  1841  			zones = append(zones, zone)
  1842  		}
  1843  	}
  1844  
  1845  	return zones, nil
  1846  }
  1847  
  1848  // expandAwsGroupEBSVolumePool expands the EBS Volume Pool block.
  1849  func expandAwsGroupEBSVolumePool(data interface{}) ([]*spotinst.AwsGroupComputeEBSVolume, error) {
  1850  	list := data.(*schema.Set).List()
  1851  	volumes := make([]*spotinst.AwsGroupComputeEBSVolume, 0, len(list))
  1852  	for _, item := range list {
  1853  		m := item.(map[string]interface{})
  1854  		volume := &spotinst.AwsGroupComputeEBSVolume{}
  1855  
  1856  		if v, ok := m["device_name"].(string); ok && v != "" {
  1857  			volume.DeviceName = spotinst.String(v)
  1858  		}
  1859  
  1860  		if v, ok := m["volume_ids"].([]interface{}); ok {
  1861  			ids := make([]string, len(v))
  1862  			for i, j := range v {
  1863  				ids[i] = j.(string)
  1864  			}
  1865  			volume.VolumeIDs = ids
  1866  		}
  1867  
  1868  		log.Printf("[DEBUG] AwsGroup EBS volume (pool) configuration: %s\n", stringutil.Stringify(volume))
  1869  		volumes = append(volumes, volume)
  1870  	}
  1871  
  1872  	return volumes, nil
  1873  }
  1874  
  1875  // expandAwsGroupSignals expands the Signal block.
  1876  func expandAwsGroupSignals(data interface{}) ([]*spotinst.AwsGroupStrategySignal, error) {
  1877  	list := data.(*schema.Set).List()
  1878  	signals := make([]*spotinst.AwsGroupStrategySignal, 0, len(list))
  1879  	for _, item := range list {
  1880  		m := item.(map[string]interface{})
  1881  		signal := &spotinst.AwsGroupStrategySignal{}
  1882  
  1883  		if v, ok := m["name"].(string); ok && v != "" {
  1884  			signal.Name = spotinst.String(strings.ToUpper(v))
  1885  		}
  1886  
  1887  		log.Printf("[DEBUG] AwsGroup signal configuration: %s\n", stringutil.Stringify(signal))
  1888  		signals = append(signals, signal)
  1889  	}
  1890  
  1891  	return signals, nil
  1892  }
  1893  
  1894  // expandAwsGroupInstanceTypes expands the Instance Types block.
  1895  func expandAwsGroupInstanceTypes(data interface{}) (*spotinst.AwsGroupComputeInstanceType, error) {
  1896  	list := data.(*schema.Set).List()
  1897  	m := list[0].(map[string]interface{})
  1898  	types := &spotinst.AwsGroupComputeInstanceType{}
  1899  	if v, ok := m["ondemand"].(string); ok && v != "" {
  1900  		types.OnDemand = spotinst.String(v)
  1901  	}
  1902  	if v, ok := m["spot"].([]interface{}); ok {
  1903  		it := make([]string, len(v))
  1904  		for i, j := range v {
  1905  			it[i] = j.(string)
  1906  		}
  1907  		types.Spot = it
  1908  	}
  1909  
  1910  	log.Printf("[DEBUG] AwsGroup instance types configuration: %s\n", stringutil.Stringify(types))
  1911  	return types, nil
  1912  }
  1913  
  1914  // expandAwsGroupNetworkInterfaces expands the Elastic Network Interface block.
  1915  func expandAwsGroupNetworkInterfaces(data interface{}) ([]*spotinst.AwsGroupComputeNetworkInterface, error) {
  1916  	list := data.(*schema.Set).List()
  1917  	interfaces := make([]*spotinst.AwsGroupComputeNetworkInterface, 0, len(list))
  1918  	for _, item := range list {
  1919  		m := item.(map[string]interface{})
  1920  		iface := &spotinst.AwsGroupComputeNetworkInterface{}
  1921  
  1922  		if v, ok := m["network_interface_id"].(string); ok && v != "" {
  1923  			iface.ID = spotinst.String(v)
  1924  		}
  1925  
  1926  		if v, ok := m["description"].(string); ok && v != "" {
  1927  			iface.Description = spotinst.String(v)
  1928  		}
  1929  
  1930  		if v, ok := m["device_index"].(int); ok && v >= 0 {
  1931  			iface.DeviceIndex = spotinst.Int(v)
  1932  		}
  1933  
  1934  		if v, ok := m["secondary_private_ip_address_count"].(int); ok && v > 0 {
  1935  			iface.SecondaryPrivateIPAddressCount = spotinst.Int(v)
  1936  		}
  1937  
  1938  		if v, ok := m["associate_public_ip_address"].(bool); ok {
  1939  			iface.AssociatePublicIPAddress = spotinst.Bool(v)
  1940  		}
  1941  
  1942  		if v, ok := m["delete_on_termination"].(bool); ok {
  1943  			iface.DeleteOnTermination = spotinst.Bool(v)
  1944  		}
  1945  
  1946  		if v, ok := m["private_ip_address"].(string); ok && v != "" {
  1947  			iface.PrivateIPAddress = spotinst.String(v)
  1948  		}
  1949  
  1950  		if v, ok := m["subnet_id"].(string); ok && v != "" {
  1951  			iface.SubnetID = spotinst.String(v)
  1952  		}
  1953  
  1954  		if v, ok := m["security_group_ids"].([]interface{}); ok {
  1955  			ids := make([]string, len(v))
  1956  			for i, j := range v {
  1957  				ids[i] = j.(string)
  1958  			}
  1959  			iface.SecurityGroupsIDs = ids
  1960  		}
  1961  
  1962  		log.Printf("[DEBUG] AwsGroup network interface configuration: %s\n", stringutil.Stringify(iface))
  1963  		interfaces = append(interfaces, iface)
  1964  	}
  1965  
  1966  	return interfaces, nil
  1967  }
  1968  
  1969  // expandAwsGroupEphemeralBlockDevice expands the Ephemeral Block Device block.
  1970  func expandAwsGroupEphemeralBlockDevices(data interface{}) ([]*spotinst.AwsGroupComputeBlockDevice, error) {
  1971  	list := data.(*schema.Set).List()
  1972  	devices := make([]*spotinst.AwsGroupComputeBlockDevice, 0, len(list))
  1973  	for _, item := range list {
  1974  		m := item.(map[string]interface{})
  1975  		device := &spotinst.AwsGroupComputeBlockDevice{}
  1976  
  1977  		if v, ok := m["device_name"].(string); ok && v != "" {
  1978  			device.DeviceName = spotinst.String(v)
  1979  		}
  1980  
  1981  		if v, ok := m["virtual_name"].(string); ok && v != "" {
  1982  			device.VirtualName = spotinst.String(v)
  1983  		}
  1984  
  1985  		log.Printf("[DEBUG] AwsGroup ephemeral block device configuration: %s\n", stringutil.Stringify(device))
  1986  		devices = append(devices, device)
  1987  	}
  1988  
  1989  	return devices, nil
  1990  }
  1991  
  1992  // expandAwsGroupEBSBlockDevices expands the EBS Block Device block.
  1993  func expandAwsGroupEBSBlockDevices(data interface{}) ([]*spotinst.AwsGroupComputeBlockDevice, error) {
  1994  	list := data.(*schema.Set).List()
  1995  	devices := make([]*spotinst.AwsGroupComputeBlockDevice, 0, len(list))
  1996  	for _, item := range list {
  1997  		m := item.(map[string]interface{})
  1998  		device := &spotinst.AwsGroupComputeBlockDevice{EBS: &spotinst.AwsGroupComputeEBS{}}
  1999  
  2000  		if v, ok := m["device_name"].(string); ok && v != "" {
  2001  			device.DeviceName = spotinst.String(v)
  2002  		}
  2003  
  2004  		if v, ok := m["delete_on_termination"].(bool); ok {
  2005  			device.EBS.DeleteOnTermination = spotinst.Bool(v)
  2006  		}
  2007  
  2008  		if v, ok := m["encrypted"].(bool); ok {
  2009  			device.EBS.Encrypted = spotinst.Bool(v)
  2010  		}
  2011  
  2012  		if v, ok := m["snapshot_id"].(string); ok && v != "" {
  2013  			device.EBS.SnapshotID = spotinst.String(v)
  2014  		}
  2015  
  2016  		if v, ok := m["volume_type"].(string); ok && v != "" {
  2017  			device.EBS.VolumeType = spotinst.String(v)
  2018  		}
  2019  
  2020  		if v, ok := m["volume_size"].(int); ok && v > 0 {
  2021  			device.EBS.VolumeSize = spotinst.Int(v)
  2022  		}
  2023  
  2024  		if v, ok := m["iops"].(int); ok && v > 0 {
  2025  			device.EBS.IOPS = spotinst.Int(v)
  2026  		}
  2027  
  2028  		log.Printf("[DEBUG] AwsGroup elastic block device configuration: %s\n", stringutil.Stringify(device))
  2029  		devices = append(devices, device)
  2030  	}
  2031  
  2032  	return devices, nil
  2033  }
  2034  
  2035  // iprofArnRE is a regular expression for matching IAM instance profile ARNs.
  2036  var iprofArnRE = regexp.MustCompile(`arn:aws:iam::\d{12}:instance-profile/?[a-zA-Z_0-9+=,.@\-_/]+`)
  2037  
  2038  // expandAwsGroupLaunchSpecification expands the launch Specification block.
  2039  func expandAwsGroupLaunchSpecification(data interface{}) (*spotinst.AwsGroupComputeLaunchSpecification, error) {
  2040  	list := data.(*schema.Set).List()
  2041  	m := list[0].(map[string]interface{})
  2042  	lc := &spotinst.AwsGroupComputeLaunchSpecification{}
  2043  
  2044  	if v, ok := m["monitoring"].(bool); ok {
  2045  		lc.Monitoring = spotinst.Bool(v)
  2046  	}
  2047  
  2048  	if v, ok := m["ebs_optimized"].(bool); ok {
  2049  		lc.EBSOptimized = spotinst.Bool(v)
  2050  	}
  2051  
  2052  	if v, ok := m["image_id"].(string); ok && v != "" {
  2053  		lc.ImageID = spotinst.String(v)
  2054  	}
  2055  
  2056  	if v, ok := m["key_pair"].(string); ok && v != "" {
  2057  		lc.KeyPair = spotinst.String(v)
  2058  	}
  2059  
  2060  	if v, ok := m["health_check_type"].(string); ok && v != "" {
  2061  		lc.HealthCheckType = spotinst.String(v)
  2062  	}
  2063  
  2064  	if v, ok := m["health_check_grace_period"].(int); ok && v > 0 {
  2065  		lc.HealthCheckGracePeriod = spotinst.Int(v)
  2066  	}
  2067  
  2068  	if v, ok := m["iam_instance_profile"].(string); ok && v != "" {
  2069  		iprof := &spotinst.AwsGroupComputeIamInstanceProfile{}
  2070  		if iprofArnRE.MatchString(v) {
  2071  			iprof.Arn = spotinst.String(v)
  2072  		} else {
  2073  			iprof.Name = spotinst.String(v)
  2074  		}
  2075  		lc.IamInstanceProfile = iprof
  2076  	}
  2077  
  2078  	if v, ok := m["user_data"].(string); ok && v != "" {
  2079  		lc.UserData = spotinst.String(base64.StdEncoding.EncodeToString([]byte(v)))
  2080  	}
  2081  
  2082  	if v, ok := m["security_group_ids"].([]interface{}); ok {
  2083  		ids := make([]string, len(v))
  2084  		for i, j := range v {
  2085  			ids[i] = j.(string)
  2086  		}
  2087  		lc.SecurityGroupIDs = ids
  2088  	}
  2089  
  2090  	if v, ok := m["load_balancer_names"].([]interface{}); ok {
  2091  		var names []string
  2092  		for _, j := range v {
  2093  			if name, ok := j.(string); ok && name != "" {
  2094  				names = append(names, name)
  2095  			}
  2096  		}
  2097  		lc.LoadBalancerNames = names
  2098  	}
  2099  
  2100  	log.Printf("[DEBUG] AwsGroup launch specification configuration: %s\n", stringutil.Stringify(lc))
  2101  	return lc, nil
  2102  }
  2103  
  2104  // expandAwsGroupLoadBalancer expands the Load Balancer block.
  2105  func expandAwsGroupLoadBalancer(data interface{}) ([]*spotinst.AwsGroupComputeLoadBalancer, error) {
  2106  	list := data.(*schema.Set).List()
  2107  	lbs := make([]*spotinst.AwsGroupComputeLoadBalancer, 0, len(list))
  2108  	for _, item := range list {
  2109  		m := item.(map[string]interface{})
  2110  		lb := &spotinst.AwsGroupComputeLoadBalancer{}
  2111  
  2112  		if v, ok := m["name"].(string); ok && v != "" {
  2113  			lb.Name = spotinst.String(v)
  2114  		}
  2115  
  2116  		if v, ok := m["arn"].(string); ok && v != "" {
  2117  			lb.Arn = spotinst.String(v)
  2118  		}
  2119  
  2120  		if v, ok := m["type"].(string); ok && v != "" {
  2121  			lb.Type = spotinst.String(strings.ToUpper(v))
  2122  		}
  2123  
  2124  		log.Printf("[DEBUG] AwsGroup load balancer configuration: %s\n", stringutil.Stringify(lb))
  2125  		lbs = append(lbs, lb)
  2126  	}
  2127  
  2128  	return lbs, nil
  2129  }
  2130  
  2131  // expandAwsGroupRancherIntegration expands the Rancher Integration block.
  2132  func expandAwsGroupRancherIntegration(data interface{}) (*spotinst.AwsGroupRancherIntegration, error) {
  2133  	list := data.(*schema.Set).List()
  2134  	m := list[0].(map[string]interface{})
  2135  	i := &spotinst.AwsGroupRancherIntegration{}
  2136  
  2137  	if v, ok := m["master_host"].(string); ok && v != "" {
  2138  		i.MasterHost = spotinst.String(v)
  2139  	}
  2140  
  2141  	if v, ok := m["access_key"].(string); ok && v != "" {
  2142  		i.AccessKey = spotinst.String(v)
  2143  	}
  2144  
  2145  	if v, ok := m["secret_key"].(string); ok && v != "" {
  2146  		i.SecretKey = spotinst.String(v)
  2147  	}
  2148  
  2149  	log.Printf("[DEBUG] AwsGroup Rancher integration configuration: %s\n", stringutil.Stringify(i))
  2150  	return i, nil
  2151  }
  2152  
  2153  // expandAwsGroupElasticBeanstalkIntegration expands the Elastic Beanstalk Integration block.
  2154  func expandAwsGroupElasticBeanstalkIntegration(data interface{}) (*spotinst.AwsGroupElasticBeanstalkIntegration, error) {
  2155  	list := data.(*schema.Set).List()
  2156  	m := list[0].(map[string]interface{})
  2157  	i := &spotinst.AwsGroupElasticBeanstalkIntegration{}
  2158  
  2159  	if v, ok := m["environment_id"].(string); ok && v != "" {
  2160  		i.EnvironmentID = spotinst.String(v)
  2161  	}
  2162  
  2163  	log.Printf("[DEBUG] AwsGroup Elastic Beanstalk integration configuration:  %s\n", stringutil.Stringify(i))
  2164  	return i, nil
  2165  }
  2166  
  2167  // expandAwsGroupEC2ContainerServiceIntegration expands the EC2 Container Service Integration block.
  2168  func expandAwsGroupEC2ContainerServiceIntegration(data interface{}) (*spotinst.AwsGroupEC2ContainerServiceIntegration, error) {
  2169  	list := data.(*schema.Set).List()
  2170  	m := list[0].(map[string]interface{})
  2171  	i := &spotinst.AwsGroupEC2ContainerServiceIntegration{}
  2172  
  2173  	if v, ok := m["cluster_name"].(string); ok && v != "" {
  2174  		i.ClusterName = spotinst.String(v)
  2175  	}
  2176  
  2177  	log.Printf("[DEBUG] AwsGroup ECS integration configuration:  %s\n", stringutil.Stringify(i))
  2178  	return i, nil
  2179  }
  2180  
  2181  // expandAwsGroupKubernetesIntegration expands the Kubernetes Integration block.
  2182  func expandAwsGroupKubernetesIntegration(data interface{}) (*spotinst.AwsGroupKubernetesIntegration, error) {
  2183  	list := data.(*schema.Set).List()
  2184  	m := list[0].(map[string]interface{})
  2185  	i := &spotinst.AwsGroupKubernetesIntegration{}
  2186  
  2187  	if v, ok := m["api_server"].(string); ok && v != "" {
  2188  		i.Server = spotinst.String(v)
  2189  	}
  2190  
  2191  	if v, ok := m["token"].(string); ok && v != "" {
  2192  		i.Token = spotinst.String(v)
  2193  	}
  2194  
  2195  	log.Printf("[DEBUG] AwsGroup Kubernetes integration configuration:  %s\n", stringutil.Stringify(i))
  2196  	return i, nil
  2197  }
  2198  
  2199  // expandAwsGroupMesosphereIntegration expands the Mesosphere Integration block.
  2200  func expandAwsGroupMesosphereIntegration(data interface{}) (*spotinst.AwsGroupMesosphereIntegration, error) {
  2201  	list := data.(*schema.Set).List()
  2202  	m := list[0].(map[string]interface{})
  2203  	i := &spotinst.AwsGroupMesosphereIntegration{}
  2204  
  2205  	if v, ok := m["api_server"].(string); ok && v != "" {
  2206  		i.Server = spotinst.String(v)
  2207  	}
  2208  
  2209  	log.Printf("[DEBUG] AwsGroup Mesosphere integration configuration: %s\n", stringutil.Stringify(i))
  2210  	return i, nil
  2211  }
  2212  
  2213  // expandAwsGroupElasticIPs expands the Elastic IPs block.
  2214  func expandAwsGroupElasticIPs(data interface{}) ([]string, error) {
  2215  	list := data.([]interface{})
  2216  	eips := make([]string, 0, len(list))
  2217  	for _, str := range list {
  2218  		if eip, ok := str.(string); ok {
  2219  			log.Printf("[DEBUG] AwsGroup elastic IP configuration: %s\n", stringutil.Stringify(eip))
  2220  			eips = append(eips, eip)
  2221  		}
  2222  	}
  2223  
  2224  	return eips, nil
  2225  }
  2226  
  2227  // expandAwsGroupTags expands the Tags block.
  2228  func expandAwsGroupTags(data interface{}) ([]*spotinst.AwsGroupComputeTag, error) {
  2229  	list := data.(map[string]interface{})
  2230  	tags := make([]*spotinst.AwsGroupComputeTag, 0, len(list))
  2231  	for k, v := range list {
  2232  		tag := &spotinst.AwsGroupComputeTag{
  2233  			Key:   spotinst.String(k),
  2234  			Value: spotinst.String(v.(string)),
  2235  		}
  2236  
  2237  		log.Printf("[DEBUG] AwsGroup tag configuration: %s\n", stringutil.Stringify(tag))
  2238  		tags = append(tags, tag)
  2239  	}
  2240  
  2241  	return tags, nil
  2242  }
  2243  
  2244  func hashAwsGroupCapacity(v interface{}) int {
  2245  	var buf bytes.Buffer
  2246  	m := v.(map[string]interface{})
  2247  
  2248  	buf.WriteString(fmt.Sprintf("%d-", m["target"].(int)))
  2249  	buf.WriteString(fmt.Sprintf("%d-", m["minimum"].(int)))
  2250  	buf.WriteString(fmt.Sprintf("%d-", m["maximum"].(int)))
  2251  
  2252  	return hashcode.String(buf.String())
  2253  }
  2254  
  2255  func hashAwsGroupStrategy(v interface{}) int {
  2256  	var buf bytes.Buffer
  2257  	m := v.(map[string]interface{})
  2258  
  2259  	buf.WriteString(fmt.Sprintf("%f-", m["risk"].(float64)))
  2260  	buf.WriteString(fmt.Sprintf("%d-", m["ondemand_count"].(int)))
  2261  	buf.WriteString(fmt.Sprintf("%t-", m["utilize_reserved_instances"].(bool)))
  2262  	buf.WriteString(fmt.Sprintf("%t-", m["fallback_to_ondemand"].(bool)))
  2263  
  2264  	return hashcode.String(buf.String())
  2265  }
  2266  
  2267  func hashAwsGroupLoadBalancer(v interface{}) int {
  2268  	var buf bytes.Buffer
  2269  	m := v.(map[string]interface{})
  2270  
  2271  	buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
  2272  	buf.WriteString(fmt.Sprintf("%s-", m["type"].(string)))
  2273  	if v, ok := m["arn"].(string); ok && len(v) > 0 {
  2274  		buf.WriteString(fmt.Sprintf("%s-", v))
  2275  	}
  2276  
  2277  	return hashcode.String(buf.String())
  2278  }
  2279  
  2280  func hashAwsGroupEBSBlockDevice(v interface{}) int {
  2281  	var buf bytes.Buffer
  2282  	m := v.(map[string]interface{})
  2283  
  2284  	buf.WriteString(fmt.Sprintf("%s-", m["device_name"].(string)))
  2285  	buf.WriteString(fmt.Sprintf("%s-", m["snapshot_id"].(string)))
  2286  	buf.WriteString(fmt.Sprintf("%d-", m["volume_size"].(int)))
  2287  	buf.WriteString(fmt.Sprintf("%t-", m["delete_on_termination"].(bool)))
  2288  	buf.WriteString(fmt.Sprintf("%t-", m["encrypted"].(bool)))
  2289  	buf.WriteString(fmt.Sprintf("%d-", m["iops"].(int)))
  2290  
  2291  	return hashcode.String(buf.String())
  2292  }
  2293  
  2294  func hashAwsGroupScalingPolicy(v interface{}) int {
  2295  	var buf bytes.Buffer
  2296  	m := v.(map[string]interface{})
  2297  
  2298  	buf.WriteString(fmt.Sprintf("%d-", m["adjustment"].(int)))
  2299  	buf.WriteString(fmt.Sprintf("%d-", m["cooldown"].(int)))
  2300  	buf.WriteString(fmt.Sprintf("%d-", m["evaluation_periods"].(int)))
  2301  	buf.WriteString(fmt.Sprintf("%s-", m["metric_name"].(string)))
  2302  	buf.WriteString(fmt.Sprintf("%s-", m["namespace"].(string)))
  2303  	buf.WriteString(fmt.Sprintf("%d-", m["period"].(int)))
  2304  	buf.WriteString(fmt.Sprintf("%s-", m["policy_name"].(string)))
  2305  	buf.WriteString(fmt.Sprintf("%s-", m["statistic"].(string)))
  2306  	buf.WriteString(fmt.Sprintf("%f-", m["threshold"].(float64)))
  2307  	buf.WriteString(fmt.Sprintf("%s-", m["unit"].(string)))
  2308  	buf.WriteString(fmt.Sprintf("%d-", m["min_target_capacity"].(int)))
  2309  	buf.WriteString(fmt.Sprintf("%d-", m["max_target_capacity"].(int)))
  2310  
  2311  	// if v, ok := m["operator"].(string); ok && len(v) > 0 {
  2312  	// 	buf.WriteString(fmt.Sprintf("%s-", v))
  2313  	// }
  2314  
  2315  	if d, ok := m["dimensions"]; ok {
  2316  		if len(d.(map[string]interface{})) > 0 {
  2317  			e := d.(map[string]interface{})
  2318  			for k, v := range e {
  2319  				buf.WriteString(fmt.Sprintf("%s:%s-", k, v.(string)))
  2320  			}
  2321  		}
  2322  	}
  2323  
  2324  	return hashcode.String(buf.String())
  2325  }
  2326  
  2327  // tagsToMap turns the list of tags into a map.
  2328  func tagsToMap(ts []*spotinst.AwsGroupComputeTag) map[string]string {
  2329  	result := make(map[string]string)
  2330  	for _, t := range ts {
  2331  		result[spotinst.StringValue(t.Key)] = spotinst.StringValue(t.Value)
  2332  	}
  2333  	return result
  2334  }