2335 lines
67 KiB
Go
Executable File
2335 lines
67 KiB
Go
Executable File
package spotinst
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha1"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"log"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/hashicorp/terraform/helper/hashcode"
|
|
"github.com/hashicorp/terraform/helper/schema"
|
|
"github.com/spotinst/spotinst-sdk-go/spotinst"
|
|
"github.com/spotinst/spotinst-sdk-go/spotinst/util/stringutil"
|
|
)
|
|
|
|
func resourceSpotinstAwsGroup() *schema.Resource {
|
|
return &schema.Resource{
|
|
Create: resourceSpotinstAwsGroupCreate,
|
|
Read: resourceSpotinstAwsGroupRead,
|
|
Update: resourceSpotinstAwsGroupUpdate,
|
|
Delete: resourceSpotinstAwsGroupDelete,
|
|
|
|
Schema: map[string]*schema.Schema{
|
|
"name": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"description": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"capacity": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Required: true,
|
|
MaxItems: 1,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"target": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Required: true,
|
|
},
|
|
|
|
"minimum": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
|
|
"maximum": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
|
|
"unit": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
Set: hashAwsGroupCapacity,
|
|
},
|
|
|
|
"strategy": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Required: true,
|
|
MaxItems: 1,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"risk": &schema.Schema{
|
|
Type: schema.TypeFloat,
|
|
Optional: true,
|
|
},
|
|
|
|
"ondemand_count": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
},
|
|
|
|
"availability_vs_cost": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
|
|
"draining_timeout": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
|
|
"utilize_reserved_instances": &schema.Schema{
|
|
Type: schema.TypeBool,
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
|
|
"fallback_to_ondemand": &schema.Schema{
|
|
Type: schema.TypeBool,
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
Set: hashAwsGroupStrategy,
|
|
},
|
|
|
|
"scheduled_task": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"task_type": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
|
|
"frequency": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
|
|
"cron_expression": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
|
|
"scale_target_capacity": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
},
|
|
|
|
"scale_min_capacity": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
},
|
|
|
|
"scale_max_capacity": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"product": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
|
|
"instance_types": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Required: true,
|
|
MaxItems: 1,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"ondemand": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"spot": &schema.Schema{
|
|
Type: schema.TypeList,
|
|
Required: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"signal": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"name": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"availability_zone": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
ConflictsWith: []string{"availability_zones"},
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"name": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"subnet_id": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"availability_zones": &schema.Schema{
|
|
Type: schema.TypeList,
|
|
Optional: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
ConflictsWith: []string{"availability_zone"},
|
|
},
|
|
|
|
"hot_ebs_volume": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"device_name": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"volume_ids": &schema.Schema{
|
|
Type: schema.TypeList,
|
|
Required: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"load_balancer": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"name": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"arn": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
|
|
"type": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
Set: hashAwsGroupLoadBalancer,
|
|
},
|
|
|
|
"launch_specification": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Required: true,
|
|
MaxItems: 1,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"load_balancer_names": &schema.Schema{
|
|
Type: schema.TypeList,
|
|
Optional: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
|
|
"monitoring": &schema.Schema{
|
|
Type: schema.TypeBool,
|
|
Optional: true,
|
|
Default: false,
|
|
},
|
|
|
|
"ebs_optimized": &schema.Schema{
|
|
Type: schema.TypeBool,
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
|
|
"image_id": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
ConflictsWith: []string{"image_id"},
|
|
},
|
|
|
|
"key_pair": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
|
|
"health_check_type": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
|
|
"health_check_grace_period": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
},
|
|
|
|
"security_group_ids": &schema.Schema{
|
|
Type: schema.TypeList,
|
|
Required: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
|
|
"user_data": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
StateFunc: func(v interface{}) string {
|
|
switch v.(type) {
|
|
case string:
|
|
hash := sha1.Sum([]byte(v.(string)))
|
|
return hex.EncodeToString(hash[:])
|
|
default:
|
|
return ""
|
|
}
|
|
},
|
|
},
|
|
|
|
"iam_role": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
Deprecated: "Attribute iam_role is deprecated. Use iam_instance_profile instead",
|
|
},
|
|
|
|
"iam_instance_profile": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"image_id": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
|
|
"elastic_ips": &schema.Schema{
|
|
Type: schema.TypeList,
|
|
Optional: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
|
|
"tags": &schema.Schema{
|
|
Type: schema.TypeMap,
|
|
Optional: true,
|
|
},
|
|
|
|
"ebs_block_device": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"delete_on_termination": &schema.Schema{
|
|
Type: schema.TypeBool,
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
|
|
"device_name": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"encrypted": &schema.Schema{
|
|
Type: schema.TypeBool,
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
|
|
"iops": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
},
|
|
|
|
"snapshot_id": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
|
|
"volume_size": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
},
|
|
|
|
"volume_type": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
Set: hashAwsGroupEBSBlockDevice,
|
|
},
|
|
|
|
"ephemeral_block_device": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"device_name": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"virtual_name": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"network_interface": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"description": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"device_index": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Required: true,
|
|
},
|
|
|
|
"secondary_private_ip_address_count": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
},
|
|
|
|
"associate_public_ip_address": &schema.Schema{
|
|
Type: schema.TypeBool,
|
|
Optional: true,
|
|
},
|
|
|
|
"delete_on_termination": &schema.Schema{
|
|
Type: schema.TypeBool,
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
|
|
"security_group_ids": &schema.Schema{
|
|
Type: schema.TypeList,
|
|
Optional: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
|
|
"network_interface_id": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
|
|
"private_ip_address": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
|
|
"subnet_id": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"scaling_up_policy": scalingPolicySchema(),
|
|
|
|
"scaling_down_policy": scalingPolicySchema(),
|
|
|
|
"rancher_integration": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
MaxItems: 1,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"master_host": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"access_key": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"secret_key": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"elastic_beanstalk_integration": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
MaxItems: 1,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"environment_id": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"ec2_container_service_integration": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
MaxItems: 1,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"cluster_name": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"kubernetes_integration": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
MaxItems: 1,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"api_server": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"token": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
"mesosphere_integration": &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
MaxItems: 1,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"api_server": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func scalingPolicySchema() *schema.Schema {
|
|
return &schema.Schema{
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
Elem: &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"policy_name": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"metric_name": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"statistic": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"unit": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"threshold": &schema.Schema{
|
|
Type: schema.TypeFloat,
|
|
Required: true,
|
|
},
|
|
|
|
"adjustment": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
},
|
|
|
|
"min_target_capacity": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
},
|
|
|
|
"max_target_capacity": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
},
|
|
|
|
"namespace": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
},
|
|
|
|
"operator": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
|
|
"evaluation_periods": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Required: true,
|
|
},
|
|
|
|
"period": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Required: true,
|
|
},
|
|
|
|
"cooldown": &schema.Schema{
|
|
Type: schema.TypeInt,
|
|
Required: true,
|
|
},
|
|
|
|
"dimensions": &schema.Schema{
|
|
Type: schema.TypeMap,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
Set: hashAwsGroupScalingPolicy,
|
|
}
|
|
}
|
|
|
|
func resourceSpotinstAwsGroupCreate(d *schema.ResourceData, meta interface{}) error {
|
|
client := meta.(*spotinst.Client)
|
|
newAwsGroup, err := buildAwsGroupOpts(d, meta)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
log.Printf("[DEBUG] AwsGroup create configuration: %s\n", stringutil.Stringify(newAwsGroup))
|
|
input := &spotinst.CreateAwsGroupInput{Group: newAwsGroup}
|
|
resp, err := client.AwsGroupService.Create(input)
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating group: %s", err)
|
|
}
|
|
d.SetId(spotinst.StringValue(resp.Group.ID))
|
|
log.Printf("[INFO] AwsGroup created successfully: %s\n", d.Id())
|
|
return resourceSpotinstAwsGroupRead(d, meta)
|
|
}
|
|
|
|
func resourceSpotinstAwsGroupRead(d *schema.ResourceData, meta interface{}) error {
|
|
client := meta.(*spotinst.Client)
|
|
input := &spotinst.ReadAwsGroupInput{ID: spotinst.String(d.Id())}
|
|
resp, err := client.AwsGroupService.Read(input)
|
|
if err != nil {
|
|
return fmt.Errorf("Error retrieving group: %s", err)
|
|
}
|
|
if g := resp.Group; g != nil {
|
|
d.Set("name", g.Name)
|
|
d.Set("description", g.Description)
|
|
d.Set("product", g.Compute.Product)
|
|
d.Set("tags", tagsToMap(g.Compute.LaunchSpecification.Tags))
|
|
d.Set("elastic_ips", g.Compute.ElasticIPs)
|
|
|
|
// Set capacity.
|
|
if g.Capacity != nil {
|
|
if err := d.Set("capacity", flattenAwsGroupCapacity(g.Capacity)); err != nil {
|
|
return fmt.Errorf("Error setting capacity onfiguration: %#v", err)
|
|
}
|
|
}
|
|
|
|
// Set strategy.
|
|
if g.Strategy != nil {
|
|
if err := d.Set("strategy", flattenAwsGroupStrategy(g.Strategy)); err != nil {
|
|
return fmt.Errorf("Error setting strategy configuration: %#v", err)
|
|
}
|
|
}
|
|
|
|
// Set signals.
|
|
if g.Strategy.Signals != nil {
|
|
if err := d.Set("signal", flattenAwsGroupSignals(g.Strategy.Signals)); err != nil {
|
|
return fmt.Errorf("Error setting signals configuration: %#v", err)
|
|
}
|
|
}
|
|
|
|
// Set scaling up policies.
|
|
if g.Scaling.Up != nil {
|
|
if err := d.Set("scaling_up_policy", flattenAwsGroupScalingPolicies(g.Scaling.Up)); err != nil {
|
|
return fmt.Errorf("Error setting scaling up policies configuration: %#v", err)
|
|
}
|
|
}
|
|
|
|
// Set scaling down policies.
|
|
if g.Scaling.Down != nil {
|
|
if err := d.Set("scaling_down_policy", flattenAwsGroupScalingPolicies(g.Scaling.Down)); err != nil {
|
|
return fmt.Errorf("Error setting scaling down policies configuration: %#v", err)
|
|
}
|
|
}
|
|
|
|
// Set scheduled tasks.
|
|
if g.Scheduling.Tasks != nil {
|
|
if err := d.Set("scheduled_task", flattenAwsGroupScheduledTasks(g.Scheduling.Tasks)); err != nil {
|
|
return fmt.Errorf("Error setting scheduled tasks configuration: %#v", err)
|
|
}
|
|
}
|
|
|
|
// Set launch specification.
|
|
if g.Compute.LaunchSpecification != nil {
|
|
imageIDSetInLaunchSpec := true
|
|
if v, ok := d.GetOk("image_id"); ok && v != "" {
|
|
imageIDSetInLaunchSpec = false
|
|
}
|
|
if err := d.Set("launch_specification", flattenAwsGroupLaunchSpecification(g.Compute.LaunchSpecification, imageIDSetInLaunchSpec)); err != nil {
|
|
return fmt.Errorf("Error setting launch specification configuration: %#v", err)
|
|
}
|
|
}
|
|
|
|
// Set image ID.
|
|
if g.Compute.LaunchSpecification.ImageID != nil {
|
|
if d.Get("image_id") != nil && d.Get("image_id") != "" {
|
|
d.Set("image_id", g.Compute.LaunchSpecification.ImageID)
|
|
}
|
|
}
|
|
|
|
// Set load balancers.
|
|
if g.Compute.LaunchSpecification.LoadBalancersConfig != nil {
|
|
if err := d.Set("load_balancer", flattenAwsGroupLoadBalancers(g.Compute.LaunchSpecification.LoadBalancersConfig.LoadBalancers)); err != nil {
|
|
return fmt.Errorf("Error setting load balancers configuration: %#v", err)
|
|
}
|
|
}
|
|
|
|
// Set EBS volume pool.
|
|
if g.Compute.EBSVolumePool != nil {
|
|
if err := d.Set("hot_ebs_volume", flattenAwsGroupEBSVolumePool(g.Compute.EBSVolumePool)); err != nil {
|
|
return fmt.Errorf("Error setting EBS volume pool configuration: %#v", err)
|
|
}
|
|
}
|
|
|
|
// Set network interfaces.
|
|
if g.Compute.LaunchSpecification.NetworkInterfaces != nil {
|
|
if err := d.Set("network_interface", flattenAwsGroupNetworkInterfaces(g.Compute.LaunchSpecification.NetworkInterfaces)); err != nil {
|
|
return fmt.Errorf("Error setting network interfaces configuration: %#v", err)
|
|
}
|
|
}
|
|
|
|
// Set block devices.
|
|
if g.Compute.LaunchSpecification.BlockDevices != nil {
|
|
if err := d.Set("ebs_block_device", flattenAwsGroupEBSBlockDevices(g.Compute.LaunchSpecification.BlockDevices)); err != nil {
|
|
return fmt.Errorf("Error setting EBS block devices configuration: %#v", err)
|
|
}
|
|
if err := d.Set("ephemeral_block_device", flattenAwsGroupEphemeralBlockDevices(g.Compute.LaunchSpecification.BlockDevices)); err != nil {
|
|
return fmt.Errorf("Error setting Ephemeral block devices configuration: %#v", err)
|
|
}
|
|
}
|
|
|
|
// Set Rancher integration.
|
|
if g.Integration.Rancher != nil {
|
|
if err := d.Set("rancher_integration", flattenAwsGroupRancherIntegration(g.Integration.Rancher)); err != nil {
|
|
return fmt.Errorf("Error setting Rancher configuration: %#v", err)
|
|
}
|
|
}
|
|
|
|
// Set Elastic Beanstalk integration.
|
|
if g.Integration.ElasticBeanstalk != nil {
|
|
if err := d.Set("elastic_beanstalk_integration", flattenAwsGroupElasticBeanstalkIntegration(g.Integration.ElasticBeanstalk)); err != nil {
|
|
return fmt.Errorf("Error setting Elastic Beanstalk configuration: %#v", err)
|
|
}
|
|
}
|
|
|
|
// Set EC2 Container Service integration.
|
|
if g.Integration.EC2ContainerService != nil {
|
|
if err := d.Set("ec2_container_service_integration", flattenAwsGroupEC2ContainerServiceIntegration(g.Integration.EC2ContainerService)); err != nil {
|
|
return fmt.Errorf("Error setting EC2 Container Service configuration: %#v", err)
|
|
}
|
|
}
|
|
|
|
// Set Kubernetes integration.
|
|
if g.Integration.Kubernetes != nil {
|
|
if err := d.Set("kubernetes_integration", flattenAwsGroupKubernetesIntegration(g.Integration.Kubernetes)); err != nil {
|
|
return fmt.Errorf("Error setting Kubernetes configuration: %#v", err)
|
|
}
|
|
}
|
|
|
|
// Set Mesosphere integration.
|
|
if g.Integration.Mesosphere != nil {
|
|
if err := d.Set("mesosphere_integration", flattenAwsGroupMesosphereIntegration(g.Integration.Mesosphere)); err != nil {
|
|
return fmt.Errorf("Error setting Mesosphere configuration: %#v", err)
|
|
}
|
|
}
|
|
} else {
|
|
d.SetId("")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func resourceSpotinstAwsGroupUpdate(d *schema.ResourceData, meta interface{}) error {
|
|
client := meta.(*spotinst.Client)
|
|
group := &spotinst.AwsGroup{ID: spotinst.String(d.Id())}
|
|
update := false
|
|
|
|
if d.HasChange("name") {
|
|
group.Name = spotinst.String(d.Get("name").(string))
|
|
update = true
|
|
}
|
|
|
|
if d.HasChange("description") {
|
|
group.Description = spotinst.String(d.Get("description").(string))
|
|
update = true
|
|
}
|
|
|
|
if d.HasChange("capacity") {
|
|
if v, ok := d.GetOk("capacity"); ok {
|
|
if capacity, err := expandAwsGroupCapacity(v); err != nil {
|
|
return err
|
|
} else {
|
|
group.Capacity = capacity
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("strategy") {
|
|
if v, ok := d.GetOk("strategy"); ok {
|
|
if strategy, err := expandAwsGroupStrategy(v); err != nil {
|
|
return err
|
|
} else {
|
|
group.Strategy = strategy
|
|
if v, ok := d.GetOk("signal"); ok {
|
|
if signals, err := expandAwsGroupSignals(v); err != nil {
|
|
return err
|
|
} else {
|
|
group.Strategy.Signals = signals
|
|
}
|
|
}
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("launch_specification") {
|
|
if v, ok := d.GetOk("launch_specification"); ok {
|
|
lc, err := expandAwsGroupLaunchSpecification(v)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if group.Compute == nil {
|
|
group.Compute = &spotinst.AwsGroupCompute{}
|
|
}
|
|
group.Compute.LaunchSpecification = lc
|
|
update = true
|
|
}
|
|
}
|
|
|
|
if d.HasChange("image_id") {
|
|
if d.Get("image_id") != nil && d.Get("image_id") != "" {
|
|
if group.Compute == nil {
|
|
group.Compute = &spotinst.AwsGroupCompute{}
|
|
}
|
|
if group.Compute.LaunchSpecification == nil {
|
|
group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{}
|
|
}
|
|
group.Compute.LaunchSpecification.ImageID = spotinst.String(d.Get("image_id").(string))
|
|
update = true
|
|
}
|
|
}
|
|
|
|
if d.HasChange("load_balancer") {
|
|
if v, ok := d.GetOk("load_balancer"); ok {
|
|
if lbs, err := expandAwsGroupLoadBalancer(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Compute == nil {
|
|
group.Compute = &spotinst.AwsGroupCompute{}
|
|
}
|
|
if group.Compute.LaunchSpecification == nil {
|
|
group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{}
|
|
}
|
|
if group.Compute.LaunchSpecification.LoadBalancersConfig == nil {
|
|
group.Compute.LaunchSpecification.LoadBalancersConfig = &spotinst.AwsGroupComputeLoadBalancersConfig{}
|
|
group.Compute.LaunchSpecification.LoadBalancersConfig.LoadBalancers = lbs
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var blockDevicesExpanded bool
|
|
|
|
if d.HasChange("ebs_block_device") {
|
|
if v, ok := d.GetOk("ebs_block_device"); ok {
|
|
if devices, err := expandAwsGroupEBSBlockDevices(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Compute == nil {
|
|
group.Compute = &spotinst.AwsGroupCompute{}
|
|
}
|
|
if group.Compute.LaunchSpecification == nil {
|
|
group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{}
|
|
}
|
|
if len(group.Compute.LaunchSpecification.BlockDevices) > 0 {
|
|
group.Compute.LaunchSpecification.BlockDevices = append(group.Compute.LaunchSpecification.BlockDevices, devices...)
|
|
} else {
|
|
if v, ok := d.GetOk("ephemeral_block_device"); ok {
|
|
if ephemeral, err := expandAwsGroupEphemeralBlockDevices(v); err != nil {
|
|
return err
|
|
} else {
|
|
devices = append(devices, ephemeral...)
|
|
blockDevicesExpanded = true
|
|
}
|
|
}
|
|
group.Compute.LaunchSpecification.BlockDevices = devices
|
|
}
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("ephemeral_block_device") && !blockDevicesExpanded {
|
|
if v, ok := d.GetOk("ephemeral_block_device"); ok {
|
|
if devices, err := expandAwsGroupEphemeralBlockDevices(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Compute == nil {
|
|
group.Compute = &spotinst.AwsGroupCompute{}
|
|
}
|
|
if group.Compute.LaunchSpecification == nil {
|
|
group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{}
|
|
}
|
|
if len(group.Compute.LaunchSpecification.BlockDevices) > 0 {
|
|
group.Compute.LaunchSpecification.BlockDevices = append(group.Compute.LaunchSpecification.BlockDevices, devices...)
|
|
} else {
|
|
if v, ok := d.GetOk("ebs_block_device"); ok {
|
|
if ebs, err := expandAwsGroupEBSBlockDevices(v); err != nil {
|
|
return err
|
|
} else {
|
|
devices = append(devices, ebs...)
|
|
}
|
|
}
|
|
group.Compute.LaunchSpecification.BlockDevices = devices
|
|
}
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("network_interface") {
|
|
if v, ok := d.GetOk("network_interface"); ok {
|
|
if interfaces, err := expandAwsGroupNetworkInterfaces(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Compute == nil {
|
|
group.Compute = &spotinst.AwsGroupCompute{}
|
|
}
|
|
if group.Compute.LaunchSpecification == nil {
|
|
group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{}
|
|
}
|
|
group.Compute.LaunchSpecification.NetworkInterfaces = interfaces
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("availability_zone") {
|
|
if v, ok := d.GetOk("availability_zone"); ok {
|
|
if zones, err := expandAwsGroupAvailabilityZones(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Compute == nil {
|
|
group.Compute = &spotinst.AwsGroupCompute{}
|
|
}
|
|
group.Compute.AvailabilityZones = zones
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("availability_zones") {
|
|
if v, ok := d.GetOk("availability_zones"); ok {
|
|
if zones, err := expandAwsGroupAvailabilityZonesSlice(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Compute == nil {
|
|
group.Compute = &spotinst.AwsGroupCompute{}
|
|
}
|
|
group.Compute.AvailabilityZones = zones
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("hot_ebs_volume") {
|
|
if v, ok := d.GetOk("hot_ebs_volume"); ok {
|
|
if ebsVolumePool, err := expandAwsGroupEBSVolumePool(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Compute == nil {
|
|
group.Compute = &spotinst.AwsGroupCompute{}
|
|
}
|
|
group.Compute.EBSVolumePool = ebsVolumePool
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("signal") {
|
|
if v, ok := d.GetOk("signal"); ok {
|
|
if signals, err := expandAwsGroupSignals(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Strategy == nil {
|
|
group.Strategy = &spotinst.AwsGroupStrategy{}
|
|
}
|
|
group.Strategy.Signals = signals
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("instance_types") {
|
|
if v, ok := d.GetOk("instance_types"); ok {
|
|
if types, err := expandAwsGroupInstanceTypes(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Compute == nil {
|
|
group.Compute = &spotinst.AwsGroupCompute{}
|
|
}
|
|
group.Compute.InstanceTypes = types
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("tags") {
|
|
if v, ok := d.GetOk("tags"); ok {
|
|
if tags, err := expandAwsGroupTags(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Compute == nil {
|
|
group.Compute = &spotinst.AwsGroupCompute{}
|
|
}
|
|
if group.Compute.LaunchSpecification == nil {
|
|
group.Compute.LaunchSpecification = &spotinst.AwsGroupComputeLaunchSpecification{}
|
|
}
|
|
group.Compute.LaunchSpecification.Tags = tags
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("elastic_ips") {
|
|
if v, ok := d.GetOk("elastic_ips"); ok {
|
|
if eips, err := expandAwsGroupElasticIPs(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Compute == nil {
|
|
group.Compute = &spotinst.AwsGroupCompute{}
|
|
}
|
|
group.Compute.ElasticIPs = eips
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("scheduled_task") {
|
|
if v, ok := d.GetOk("scheduled_task"); ok {
|
|
if tasks, err := expandAwsGroupScheduledTasks(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Scheduling == nil {
|
|
group.Scheduling = &spotinst.AwsGroupScheduling{}
|
|
}
|
|
group.Scheduling.Tasks = tasks
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("scaling_up_policy") {
|
|
if v, ok := d.GetOk("scaling_up_policy"); ok {
|
|
if policies, err := expandAwsGroupScalingPolicies(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Scaling == nil {
|
|
group.Scaling = &spotinst.AwsGroupScaling{}
|
|
}
|
|
group.Scaling.Up = policies
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("scaling_down_policy") {
|
|
if v, ok := d.GetOk("scaling_down_policy"); ok {
|
|
if policies, err := expandAwsGroupScalingPolicies(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Scaling == nil {
|
|
group.Scaling = &spotinst.AwsGroupScaling{}
|
|
}
|
|
group.Scaling.Down = policies
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("rancher_integration") {
|
|
if v, ok := d.GetOk("rancher_integration"); ok {
|
|
if integration, err := expandAwsGroupRancherIntegration(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Integration == nil {
|
|
group.Integration = &spotinst.AwsGroupIntegration{}
|
|
}
|
|
group.Integration.Rancher = integration
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("elastic_eanstalk_integration") {
|
|
if v, ok := d.GetOk("elastic_beanstalk_integration"); ok {
|
|
if integration, err := expandAwsGroupElasticBeanstalkIntegration(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Integration == nil {
|
|
group.Integration = &spotinst.AwsGroupIntegration{}
|
|
}
|
|
group.Integration.ElasticBeanstalk = integration
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("ec2_container_service_integration") {
|
|
if v, ok := d.GetOk("ec2_container_service_integration"); ok {
|
|
if integration, err := expandAwsGroupEC2ContainerServiceIntegration(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Integration == nil {
|
|
group.Integration = &spotinst.AwsGroupIntegration{}
|
|
}
|
|
group.Integration.EC2ContainerService = integration
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("kubernetes_integration") {
|
|
if v, ok := d.GetOk("kubernetes_integration"); ok {
|
|
if integration, err := expandAwsGroupKubernetesIntegration(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Integration == nil {
|
|
group.Integration = &spotinst.AwsGroupIntegration{}
|
|
}
|
|
group.Integration.Kubernetes = integration
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.HasChange("mesosphere_integration") {
|
|
if v, ok := d.GetOk("mesosphere_integration"); ok {
|
|
if integration, err := expandAwsGroupMesosphereIntegration(v); err != nil {
|
|
return err
|
|
} else {
|
|
if group.Integration == nil {
|
|
group.Integration = &spotinst.AwsGroupIntegration{}
|
|
}
|
|
group.Integration.Mesosphere = integration
|
|
update = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if update {
|
|
log.Printf("[DEBUG] AwsGroup update configuration: %s\n", stringutil.Stringify(group))
|
|
input := &spotinst.UpdateAwsGroupInput{Group: group}
|
|
if _, err := client.AwsGroupService.Update(input); err != nil {
|
|
return fmt.Errorf("Error updating group %s: %s", d.Id(), err)
|
|
}
|
|
}
|
|
|
|
return resourceSpotinstAwsGroupRead(d, meta)
|
|
}
|
|
|
|
func resourceSpotinstAwsGroupDelete(d *schema.ResourceData, meta interface{}) error {
|
|
client := meta.(*spotinst.Client)
|
|
log.Printf("[INFO] Deleting group: %s\n", d.Id())
|
|
input := &spotinst.DeleteAwsGroupInput{ID: spotinst.String(d.Id())}
|
|
if _, err := client.AwsGroupService.Delete(input); err != nil {
|
|
return fmt.Errorf("Error deleting group: %s", err)
|
|
}
|
|
d.SetId("")
|
|
return nil
|
|
}
|
|
|
|
func flattenAwsGroupCapacity(capacity *spotinst.AwsGroupCapacity) []interface{} {
|
|
result := make(map[string]interface{})
|
|
result["target"] = spotinst.IntValue(capacity.Target)
|
|
result["minimum"] = spotinst.IntValue(capacity.Minimum)
|
|
result["maximum"] = spotinst.IntValue(capacity.Maximum)
|
|
result["unit"] = spotinst.StringValue(capacity.Unit)
|
|
return []interface{}{result}
|
|
}
|
|
|
|
func flattenAwsGroupStrategy(strategy *spotinst.AwsGroupStrategy) []interface{} {
|
|
result := make(map[string]interface{})
|
|
result["risk"] = spotinst.Float64Value(strategy.Risk)
|
|
result["ondemand_count"] = spotinst.IntValue(strategy.OnDemandCount)
|
|
result["availability_vs_cost"] = spotinst.StringValue(strategy.AvailabilityVsCost)
|
|
result["draining_timeout"] = spotinst.IntValue(strategy.DrainingTimeout)
|
|
result["utilize_reserved_instances"] = spotinst.BoolValue(strategy.UtilizeReservedInstances)
|
|
result["fallback_to_ondemand"] = spotinst.BoolValue(strategy.FallbackToOnDemand)
|
|
return []interface{}{result}
|
|
}
|
|
|
|
func flattenAwsGroupLaunchSpecification(lspec *spotinst.AwsGroupComputeLaunchSpecification, includeImageID bool) []interface{} {
|
|
result := make(map[string]interface{})
|
|
result["health_check_grace_period"] = spotinst.IntValue(lspec.HealthCheckGracePeriod)
|
|
result["health_check_type"] = spotinst.StringValue(lspec.HealthCheckType)
|
|
if includeImageID {
|
|
result["image_id"] = spotinst.StringValue(lspec.ImageID)
|
|
}
|
|
result["key_pair"] = spotinst.StringValue(lspec.KeyPair)
|
|
if lspec.UserData != nil && spotinst.StringValue(lspec.UserData) != "" {
|
|
decodedUserData, _ := base64.StdEncoding.DecodeString(spotinst.StringValue(lspec.UserData))
|
|
result["user_data"] = string(decodedUserData)
|
|
} else {
|
|
result["user_data"] = ""
|
|
}
|
|
result["monitoring"] = spotinst.BoolValue(lspec.Monitoring)
|
|
result["ebs_optimized"] = spotinst.BoolValue(lspec.EBSOptimized)
|
|
result["load_balancer_names"] = lspec.LoadBalancerNames
|
|
result["security_group_ids"] = lspec.SecurityGroupIDs
|
|
if lspec.IamInstanceProfile != nil {
|
|
if lspec.IamInstanceProfile.Arn != nil {
|
|
result["iam_instance_profile"] = spotinst.StringValue(lspec.IamInstanceProfile.Arn)
|
|
} else {
|
|
result["iam_instance_profile"] = spotinst.StringValue(lspec.IamInstanceProfile.Name)
|
|
}
|
|
}
|
|
return []interface{}{result}
|
|
}
|
|
|
|
func flattenAwsGroupLoadBalancers(balancers []*spotinst.AwsGroupComputeLoadBalancer) []interface{} {
|
|
result := make([]interface{}, 0, len(balancers))
|
|
for _, b := range balancers {
|
|
m := make(map[string]interface{})
|
|
m["name"] = spotinst.StringValue(b.Name)
|
|
m["arn"] = spotinst.StringValue(b.Arn)
|
|
m["type"] = strings.ToLower(spotinst.StringValue(b.Type))
|
|
result = append(result, m)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func flattenAwsGroupEBSVolumePool(volumes []*spotinst.AwsGroupComputeEBSVolume) []interface{} {
|
|
result := make([]interface{}, 0, len(volumes))
|
|
for _, v := range volumes {
|
|
m := make(map[string]interface{})
|
|
m["device_name"] = spotinst.StringValue(v.DeviceName)
|
|
m["volume_ids"] = v.VolumeIDs
|
|
result = append(result, m)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func flattenAwsGroupSignals(signals []*spotinst.AwsGroupStrategySignal) []interface{} {
|
|
result := make([]interface{}, 0, len(signals))
|
|
for _, s := range signals {
|
|
m := make(map[string]interface{})
|
|
m["name"] = strings.ToLower(spotinst.StringValue(s.Name))
|
|
result = append(result, m)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func flattenAwsGroupScheduledTasks(tasks []*spotinst.AwsGroupScheduledTask) []interface{} {
|
|
result := make([]interface{}, 0, len(tasks))
|
|
for _, t := range tasks {
|
|
m := make(map[string]interface{})
|
|
m["task_type"] = spotinst.StringValue(t.TaskType)
|
|
m["cron_expression"] = spotinst.StringValue(t.CronExpression)
|
|
m["frequency"] = spotinst.StringValue(t.Frequency)
|
|
m["scale_target_capacity"] = spotinst.IntValue(t.ScaleTargetCapacity)
|
|
m["scale_min_capacity"] = spotinst.IntValue(t.ScaleMinCapacity)
|
|
m["scale_max_capacity"] = spotinst.IntValue(t.ScaleMaxCapacity)
|
|
result = append(result, m)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func flattenAwsGroupScalingPolicies(policies []*spotinst.AwsGroupScalingPolicy) []interface{} {
|
|
result := make([]interface{}, 0, len(policies))
|
|
for _, p := range policies {
|
|
m := make(map[string]interface{})
|
|
m["adjustment"] = spotinst.IntValue(p.Adjustment)
|
|
m["cooldown"] = spotinst.IntValue(p.Cooldown)
|
|
m["evaluation_periods"] = spotinst.IntValue(p.EvaluationPeriods)
|
|
m["min_target_capacity"] = spotinst.IntValue(p.MinTargetCapacity)
|
|
m["max_target_capacity"] = spotinst.IntValue(p.MaxTargetCapacity)
|
|
m["metric_name"] = spotinst.StringValue(p.MetricName)
|
|
m["namespace"] = spotinst.StringValue(p.Namespace)
|
|
m["operator"] = spotinst.StringValue(p.Operator)
|
|
m["period"] = spotinst.IntValue(p.Period)
|
|
m["policy_name"] = spotinst.StringValue(p.PolicyName)
|
|
m["statistic"] = spotinst.StringValue(p.Statistic)
|
|
m["threshold"] = spotinst.Float64Value(p.Threshold)
|
|
m["unit"] = spotinst.StringValue(p.Unit)
|
|
if len(p.Dimensions) > 0 {
|
|
flatDims := make(map[string]interface{})
|
|
for _, d := range p.Dimensions {
|
|
flatDims[spotinst.StringValue(d.Name)] = *d.Value
|
|
}
|
|
m["dimensions"] = flatDims
|
|
}
|
|
result = append(result, m)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func flattenAwsGroupNetworkInterfaces(ifaces []*spotinst.AwsGroupComputeNetworkInterface) []interface{} {
|
|
result := make([]interface{}, 0, len(ifaces))
|
|
for _, iface := range ifaces {
|
|
m := make(map[string]interface{})
|
|
m["associate_public_ip_address"] = spotinst.BoolValue(iface.AssociatePublicIPAddress)
|
|
m["delete_on_termination"] = spotinst.BoolValue(iface.DeleteOnTermination)
|
|
m["description"] = spotinst.StringValue(iface.Description)
|
|
m["device_index"] = spotinst.IntValue(iface.DeviceIndex)
|
|
m["network_interface_id"] = spotinst.StringValue(iface.ID)
|
|
m["private_ip_address"] = spotinst.StringValue(iface.PrivateIPAddress)
|
|
m["secondary_private_ip_address_count"] = spotinst.IntValue(iface.SecondaryPrivateIPAddressCount)
|
|
m["subnet_id"] = spotinst.StringValue(iface.SubnetID)
|
|
m["security_group_ids"] = iface.SecurityGroupsIDs
|
|
result = append(result, m)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func flattenAwsGroupEBSBlockDevices(devices []*spotinst.AwsGroupComputeBlockDevice) []interface{} {
|
|
result := make([]interface{}, 0, len(devices))
|
|
for _, dev := range devices {
|
|
if dev.EBS != nil {
|
|
m := make(map[string]interface{})
|
|
m["device_name"] = spotinst.StringValue(dev.DeviceName)
|
|
m["delete_on_termination"] = spotinst.BoolValue(dev.EBS.DeleteOnTermination)
|
|
m["encrypted"] = spotinst.BoolValue(dev.EBS.Encrypted)
|
|
m["iops"] = spotinst.IntValue(dev.EBS.IOPS)
|
|
m["snapshot_id"] = spotinst.StringValue(dev.EBS.SnapshotID)
|
|
m["volume_type"] = spotinst.StringValue(dev.EBS.VolumeType)
|
|
m["volume_size"] = spotinst.IntValue(dev.EBS.VolumeSize)
|
|
result = append(result, m)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func flattenAwsGroupEphemeralBlockDevices(devices []*spotinst.AwsGroupComputeBlockDevice) []interface{} {
|
|
result := make([]interface{}, 0, len(devices))
|
|
for _, dev := range devices {
|
|
if dev.EBS == nil {
|
|
m := make(map[string]interface{})
|
|
m["device_name"] = spotinst.StringValue(dev.DeviceName)
|
|
m["virtual_name"] = spotinst.StringValue(dev.VirtualName)
|
|
result = append(result, m)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func flattenAwsGroupRancherIntegration(integration *spotinst.AwsGroupRancherIntegration) []interface{} {
|
|
result := make(map[string]interface{})
|
|
result["master_host"] = spotinst.StringValue(integration.MasterHost)
|
|
result["access_key"] = spotinst.StringValue(integration.AccessKey)
|
|
result["secret_key"] = spotinst.StringValue(integration.SecretKey)
|
|
return []interface{}{result}
|
|
}
|
|
|
|
func flattenAwsGroupElasticBeanstalkIntegration(integration *spotinst.AwsGroupElasticBeanstalkIntegration) []interface{} {
|
|
result := make(map[string]interface{})
|
|
result["environment_id"] = spotinst.StringValue(integration.EnvironmentID)
|
|
return []interface{}{result}
|
|
}
|
|
|
|
func flattenAwsGroupEC2ContainerServiceIntegration(integration *spotinst.AwsGroupEC2ContainerServiceIntegration) []interface{} {
|
|
result := make(map[string]interface{})
|
|
result["cluster_name"] = spotinst.StringValue(integration.ClusterName)
|
|
return []interface{}{result}
|
|
}
|
|
|
|
func flattenAwsGroupKubernetesIntegration(integration *spotinst.AwsGroupKubernetesIntegration) []interface{} {
|
|
result := make(map[string]interface{})
|
|
result["api_server"] = spotinst.StringValue(integration.Server)
|
|
result["token"] = spotinst.StringValue(integration.Token)
|
|
return []interface{}{result}
|
|
}
|
|
|
|
func flattenAwsGroupMesosphereIntegration(integration *spotinst.AwsGroupMesosphereIntegration) []interface{} {
|
|
result := make(map[string]interface{})
|
|
result["api_server"] = spotinst.StringValue(integration.Server)
|
|
return []interface{}{result}
|
|
}
|
|
|
|
// buildAwsGroupOpts builds the Spotinst AWS Group options.
|
|
func buildAwsGroupOpts(d *schema.ResourceData, meta interface{}) (*spotinst.AwsGroup, error) {
|
|
group := &spotinst.AwsGroup{
|
|
Name: spotinst.String(d.Get("name").(string)),
|
|
Description: spotinst.String(d.Get("description").(string)),
|
|
Scaling: &spotinst.AwsGroupScaling{},
|
|
Scheduling: &spotinst.AwsGroupScheduling{},
|
|
Integration: &spotinst.AwsGroupIntegration{},
|
|
Compute: &spotinst.AwsGroupCompute{
|
|
Product: spotinst.String(d.Get("product").(string)),
|
|
LaunchSpecification: &spotinst.AwsGroupComputeLaunchSpecification{},
|
|
},
|
|
}
|
|
|
|
if v, ok := d.GetOk("capacity"); ok {
|
|
if capacity, err := expandAwsGroupCapacity(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Capacity = capacity
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("strategy"); ok {
|
|
if strategy, err := expandAwsGroupStrategy(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Strategy = strategy
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("scaling_up_policy"); ok {
|
|
if policies, err := expandAwsGroupScalingPolicies(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Scaling.Up = policies
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("scaling_down_policy"); ok {
|
|
if policies, err := expandAwsGroupScalingPolicies(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Scaling.Down = policies
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("scheduled_task"); ok {
|
|
if tasks, err := expandAwsGroupScheduledTasks(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Scheduling.Tasks = tasks
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("instance_types"); ok {
|
|
if types, err := expandAwsGroupInstanceTypes(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Compute.InstanceTypes = types
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("elastic_ips"); ok {
|
|
if eips, err := expandAwsGroupElasticIPs(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Compute.ElasticIPs = eips
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("availability_zone"); ok {
|
|
if zones, err := expandAwsGroupAvailabilityZones(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Compute.AvailabilityZones = zones
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("availability_zones"); ok {
|
|
if zones, err := expandAwsGroupAvailabilityZonesSlice(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Compute.AvailabilityZones = zones
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("hot_ebs_volume"); ok {
|
|
if ebsVolumePool, err := expandAwsGroupEBSVolumePool(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Compute.EBSVolumePool = ebsVolumePool
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("signal"); ok {
|
|
if signals, err := expandAwsGroupSignals(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Strategy.Signals = signals
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("launch_specification"); ok {
|
|
if lc, err := expandAwsGroupLaunchSpecification(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Compute.LaunchSpecification = lc
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("image_id"); ok {
|
|
group.Compute.LaunchSpecification.ImageID = spotinst.String(v.(string))
|
|
}
|
|
|
|
if v, ok := d.GetOk("load_balancer"); ok {
|
|
if lbs, err := expandAwsGroupLoadBalancer(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
if group.Compute.LaunchSpecification.LoadBalancersConfig == nil {
|
|
group.Compute.LaunchSpecification.LoadBalancersConfig = &spotinst.AwsGroupComputeLoadBalancersConfig{}
|
|
}
|
|
group.Compute.LaunchSpecification.LoadBalancersConfig.LoadBalancers = lbs
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("tags"); ok {
|
|
if tags, err := expandAwsGroupTags(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Compute.LaunchSpecification.Tags = tags
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("network_interface"); ok {
|
|
if interfaces, err := expandAwsGroupNetworkInterfaces(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Compute.LaunchSpecification.NetworkInterfaces = interfaces
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("ebs_block_device"); ok {
|
|
if devices, err := expandAwsGroupEBSBlockDevices(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Compute.LaunchSpecification.BlockDevices = devices
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("ephemeral_block_device"); ok {
|
|
if devices, err := expandAwsGroupEphemeralBlockDevices(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
if len(group.Compute.LaunchSpecification.BlockDevices) > 0 {
|
|
group.Compute.LaunchSpecification.BlockDevices = append(group.Compute.LaunchSpecification.BlockDevices, devices...)
|
|
} else {
|
|
group.Compute.LaunchSpecification.BlockDevices = devices
|
|
}
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("rancher_integration"); ok {
|
|
if integration, err := expandAwsGroupRancherIntegration(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Integration.Rancher = integration
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("elastic_beanstalk_integration"); ok {
|
|
if integration, err := expandAwsGroupElasticBeanstalkIntegration(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Integration.ElasticBeanstalk = integration
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("ec2_container_service_integration"); ok {
|
|
if integration, err := expandAwsGroupEC2ContainerServiceIntegration(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Integration.EC2ContainerService = integration
|
|
}
|
|
}
|
|
|
|
if v, ok := d.GetOk("kubernetes_integration"); ok {
|
|
if integration, err := expandAwsGroupKubernetesIntegration(v); err != nil {
|
|
return nil, err
|
|
} else {
|
|
group.Integration.Kubernetes = integration
|
|
}
|
|
}
|
|
|
|
return group, nil
|
|
}
|
|
|
|
// expandAwsGroupCapacity expands the Capacity block.
|
|
func expandAwsGroupCapacity(data interface{}) (*spotinst.AwsGroupCapacity, error) {
|
|
list := data.(*schema.Set).List()
|
|
m := list[0].(map[string]interface{})
|
|
capacity := &spotinst.AwsGroupCapacity{}
|
|
|
|
if v, ok := m["minimum"].(int); ok && v >= 0 {
|
|
capacity.Minimum = spotinst.Int(v)
|
|
}
|
|
|
|
if v, ok := m["maximum"].(int); ok && v >= 0 {
|
|
capacity.Maximum = spotinst.Int(v)
|
|
}
|
|
|
|
if v, ok := m["target"].(int); ok && v >= 0 {
|
|
capacity.Target = spotinst.Int(v)
|
|
}
|
|
|
|
if v, ok := m["unit"].(string); ok && v != "" {
|
|
capacity.Unit = spotinst.String(v)
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup capacity configuration: %s\n", stringutil.Stringify(capacity))
|
|
return capacity, nil
|
|
}
|
|
|
|
// expandAwsGroupStrategy expands the Strategy block.
|
|
func expandAwsGroupStrategy(data interface{}) (*spotinst.AwsGroupStrategy, error) {
|
|
list := data.(*schema.Set).List()
|
|
m := list[0].(map[string]interface{})
|
|
strategy := &spotinst.AwsGroupStrategy{}
|
|
|
|
if v, ok := m["risk"].(float64); ok && v >= 0 {
|
|
strategy.Risk = spotinst.Float64(v)
|
|
}
|
|
|
|
if v, ok := m["ondemand_count"].(int); ok && v >= 0 && spotinst.Float64Value(strategy.Risk) == 0 {
|
|
strategy.OnDemandCount = spotinst.Int(v)
|
|
strategy.Risk = nil
|
|
}
|
|
|
|
if v, ok := m["availability_vs_cost"].(string); ok && v != "" {
|
|
strategy.AvailabilityVsCost = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["draining_timeout"].(int); ok && v > 0 {
|
|
strategy.DrainingTimeout = spotinst.Int(v)
|
|
}
|
|
|
|
if v, ok := m["utilize_reserved_instances"].(bool); ok {
|
|
strategy.UtilizeReservedInstances = spotinst.Bool(v)
|
|
}
|
|
|
|
if v, ok := m["fallback_to_ondemand"].(bool); ok {
|
|
strategy.FallbackToOnDemand = spotinst.Bool(v)
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup strategy configuration: %s\n", stringutil.Stringify(strategy))
|
|
return strategy, nil
|
|
}
|
|
|
|
// expandAwsGroupScalingPolicies expands the Scaling Policy block.
|
|
func expandAwsGroupScalingPolicies(data interface{}) ([]*spotinst.AwsGroupScalingPolicy, error) {
|
|
list := data.(*schema.Set).List()
|
|
policies := make([]*spotinst.AwsGroupScalingPolicy, 0, len(list))
|
|
for _, item := range list {
|
|
m := item.(map[string]interface{})
|
|
policy := &spotinst.AwsGroupScalingPolicy{}
|
|
|
|
if v, ok := m["policy_name"].(string); ok && v != "" {
|
|
policy.PolicyName = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["metric_name"].(string); ok && v != "" {
|
|
policy.MetricName = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["statistic"].(string); ok && v != "" {
|
|
policy.Statistic = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["unit"].(string); ok && v != "" {
|
|
policy.Unit = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["threshold"].(float64); ok && v > 0 {
|
|
policy.Threshold = spotinst.Float64(v)
|
|
}
|
|
|
|
if v, ok := m["adjustment"].(int); ok && v > 0 {
|
|
policy.Adjustment = spotinst.Int(v)
|
|
}
|
|
|
|
if v, ok := m["min_target_capacity"].(int); ok && v > 0 {
|
|
policy.MinTargetCapacity = spotinst.Int(v)
|
|
}
|
|
|
|
if v, ok := m["max_target_capacity"].(int); ok && v > 0 {
|
|
policy.MaxTargetCapacity = spotinst.Int(v)
|
|
}
|
|
|
|
if v, ok := m["namespace"].(string); ok && v != "" {
|
|
policy.Namespace = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["operator"].(string); ok && v != "" {
|
|
policy.Operator = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["period"].(int); ok && v > 0 {
|
|
policy.Period = spotinst.Int(v)
|
|
}
|
|
|
|
if v, ok := m["evaluation_periods"].(int); ok && v > 0 {
|
|
policy.EvaluationPeriods = spotinst.Int(v)
|
|
}
|
|
|
|
if v, ok := m["cooldown"].(int); ok && v > 0 {
|
|
policy.Cooldown = spotinst.Int(v)
|
|
}
|
|
|
|
if v, ok := m["dimensions"]; ok {
|
|
dimensions := expandAwsGroupScalingPolicyDimensions(v.(map[string]interface{}))
|
|
policy.Dimensions = dimensions
|
|
}
|
|
|
|
if v, ok := m["namespace"].(string); ok && v != "" {
|
|
log.Printf("[DEBUG] AwsGroup scaling policy configuration: %s\n", stringutil.Stringify(policy))
|
|
policies = append(policies, policy)
|
|
}
|
|
}
|
|
|
|
return policies, nil
|
|
}
|
|
|
|
func expandAwsGroupScalingPolicyDimensions(list map[string]interface{}) []*spotinst.AwsGroupScalingPolicyDimension {
|
|
dimensions := make([]*spotinst.AwsGroupScalingPolicyDimension, 0, len(list))
|
|
for name, val := range list {
|
|
dimension := &spotinst.AwsGroupScalingPolicyDimension{
|
|
Name: spotinst.String(name),
|
|
Value: spotinst.String(val.(string)),
|
|
}
|
|
log.Printf("[DEBUG] AwsGroup scaling policy dimension: %s\n", stringutil.Stringify(dimension))
|
|
dimensions = append(dimensions, dimension)
|
|
}
|
|
return dimensions
|
|
}
|
|
|
|
// expandAwsGroupScheduledTasks expands the Scheduled Task block.
|
|
func expandAwsGroupScheduledTasks(data interface{}) ([]*spotinst.AwsGroupScheduledTask, error) {
|
|
list := data.(*schema.Set).List()
|
|
tasks := make([]*spotinst.AwsGroupScheduledTask, 0, len(list))
|
|
for _, item := range list {
|
|
m := item.(map[string]interface{})
|
|
task := &spotinst.AwsGroupScheduledTask{}
|
|
|
|
if v, ok := m["task_type"].(string); ok && v != "" {
|
|
task.TaskType = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["frequency"].(string); ok && v != "" {
|
|
task.Frequency = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["cron_expression"].(string); ok && v != "" {
|
|
task.CronExpression = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["scale_target_capacity"].(int); ok && v > 0 {
|
|
task.ScaleTargetCapacity = spotinst.Int(v)
|
|
}
|
|
|
|
if v, ok := m["scale_min_capacity"].(int); ok && v > 0 {
|
|
task.ScaleMinCapacity = spotinst.Int(v)
|
|
}
|
|
|
|
if v, ok := m["scale_max_capacity"].(int); ok && v > 0 {
|
|
task.ScaleMaxCapacity = spotinst.Int(v)
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup scheduled task configuration: %s\n", stringutil.Stringify(task))
|
|
tasks = append(tasks, task)
|
|
}
|
|
|
|
return tasks, nil
|
|
}
|
|
|
|
// expandAwsGroupAvailabilityZones expands the Availability Zone block.
|
|
func expandAwsGroupAvailabilityZones(data interface{}) ([]*spotinst.AwsGroupComputeAvailabilityZone, error) {
|
|
list := data.(*schema.Set).List()
|
|
zones := make([]*spotinst.AwsGroupComputeAvailabilityZone, 0, len(list))
|
|
for _, item := range list {
|
|
m := item.(map[string]interface{})
|
|
zone := &spotinst.AwsGroupComputeAvailabilityZone{}
|
|
|
|
if v, ok := m["name"].(string); ok && v != "" {
|
|
zone.Name = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["subnet_id"].(string); ok && v != "" {
|
|
zone.SubnetID = spotinst.String(v)
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup availability zone configuration: %s\n", stringutil.Stringify(zone))
|
|
zones = append(zones, zone)
|
|
}
|
|
|
|
return zones, nil
|
|
}
|
|
|
|
// expandAwsGroupAvailabilityZonesSlice expands the Availability Zone block when provided as a slice.
|
|
func expandAwsGroupAvailabilityZonesSlice(data interface{}) ([]*spotinst.AwsGroupComputeAvailabilityZone, error) {
|
|
list := data.([]interface{})
|
|
zones := make([]*spotinst.AwsGroupComputeAvailabilityZone, 0, len(list))
|
|
for _, str := range list {
|
|
if s, ok := str.(string); ok {
|
|
parts := strings.Split(s, ":")
|
|
zone := &spotinst.AwsGroupComputeAvailabilityZone{}
|
|
if len(parts) >= 1 && parts[0] != "" {
|
|
zone.Name = spotinst.String(parts[0])
|
|
}
|
|
if len(parts) == 2 && parts[1] != "" {
|
|
zone.SubnetID = spotinst.String(parts[1])
|
|
}
|
|
log.Printf("[DEBUG] AwsGroup availability zone configuration: %s\n", stringutil.Stringify(zone))
|
|
zones = append(zones, zone)
|
|
}
|
|
}
|
|
|
|
return zones, nil
|
|
}
|
|
|
|
// expandAwsGroupEBSVolumePool expands the EBS Volume Pool block.
|
|
func expandAwsGroupEBSVolumePool(data interface{}) ([]*spotinst.AwsGroupComputeEBSVolume, error) {
|
|
list := data.(*schema.Set).List()
|
|
volumes := make([]*spotinst.AwsGroupComputeEBSVolume, 0, len(list))
|
|
for _, item := range list {
|
|
m := item.(map[string]interface{})
|
|
volume := &spotinst.AwsGroupComputeEBSVolume{}
|
|
|
|
if v, ok := m["device_name"].(string); ok && v != "" {
|
|
volume.DeviceName = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["volume_ids"].([]interface{}); ok {
|
|
ids := make([]string, len(v))
|
|
for i, j := range v {
|
|
ids[i] = j.(string)
|
|
}
|
|
volume.VolumeIDs = ids
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup EBS volume (pool) configuration: %s\n", stringutil.Stringify(volume))
|
|
volumes = append(volumes, volume)
|
|
}
|
|
|
|
return volumes, nil
|
|
}
|
|
|
|
// expandAwsGroupSignals expands the Signal block.
|
|
func expandAwsGroupSignals(data interface{}) ([]*spotinst.AwsGroupStrategySignal, error) {
|
|
list := data.(*schema.Set).List()
|
|
signals := make([]*spotinst.AwsGroupStrategySignal, 0, len(list))
|
|
for _, item := range list {
|
|
m := item.(map[string]interface{})
|
|
signal := &spotinst.AwsGroupStrategySignal{}
|
|
|
|
if v, ok := m["name"].(string); ok && v != "" {
|
|
signal.Name = spotinst.String(strings.ToUpper(v))
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup signal configuration: %s\n", stringutil.Stringify(signal))
|
|
signals = append(signals, signal)
|
|
}
|
|
|
|
return signals, nil
|
|
}
|
|
|
|
// expandAwsGroupInstanceTypes expands the Instance Types block.
|
|
func expandAwsGroupInstanceTypes(data interface{}) (*spotinst.AwsGroupComputeInstanceType, error) {
|
|
list := data.(*schema.Set).List()
|
|
m := list[0].(map[string]interface{})
|
|
types := &spotinst.AwsGroupComputeInstanceType{}
|
|
if v, ok := m["ondemand"].(string); ok && v != "" {
|
|
types.OnDemand = spotinst.String(v)
|
|
}
|
|
if v, ok := m["spot"].([]interface{}); ok {
|
|
it := make([]string, len(v))
|
|
for i, j := range v {
|
|
it[i] = j.(string)
|
|
}
|
|
types.Spot = it
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup instance types configuration: %s\n", stringutil.Stringify(types))
|
|
return types, nil
|
|
}
|
|
|
|
// expandAwsGroupNetworkInterfaces expands the Elastic Network Interface block.
|
|
func expandAwsGroupNetworkInterfaces(data interface{}) ([]*spotinst.AwsGroupComputeNetworkInterface, error) {
|
|
list := data.(*schema.Set).List()
|
|
interfaces := make([]*spotinst.AwsGroupComputeNetworkInterface, 0, len(list))
|
|
for _, item := range list {
|
|
m := item.(map[string]interface{})
|
|
iface := &spotinst.AwsGroupComputeNetworkInterface{}
|
|
|
|
if v, ok := m["network_interface_id"].(string); ok && v != "" {
|
|
iface.ID = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["description"].(string); ok && v != "" {
|
|
iface.Description = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["device_index"].(int); ok && v >= 0 {
|
|
iface.DeviceIndex = spotinst.Int(v)
|
|
}
|
|
|
|
if v, ok := m["secondary_private_ip_address_count"].(int); ok && v > 0 {
|
|
iface.SecondaryPrivateIPAddressCount = spotinst.Int(v)
|
|
}
|
|
|
|
if v, ok := m["associate_public_ip_address"].(bool); ok {
|
|
iface.AssociatePublicIPAddress = spotinst.Bool(v)
|
|
}
|
|
|
|
if v, ok := m["delete_on_termination"].(bool); ok {
|
|
iface.DeleteOnTermination = spotinst.Bool(v)
|
|
}
|
|
|
|
if v, ok := m["private_ip_address"].(string); ok && v != "" {
|
|
iface.PrivateIPAddress = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["subnet_id"].(string); ok && v != "" {
|
|
iface.SubnetID = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["security_group_ids"].([]interface{}); ok {
|
|
ids := make([]string, len(v))
|
|
for i, j := range v {
|
|
ids[i] = j.(string)
|
|
}
|
|
iface.SecurityGroupsIDs = ids
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup network interface configuration: %s\n", stringutil.Stringify(iface))
|
|
interfaces = append(interfaces, iface)
|
|
}
|
|
|
|
return interfaces, nil
|
|
}
|
|
|
|
// expandAwsGroupEphemeralBlockDevice expands the Ephemeral Block Device block.
|
|
func expandAwsGroupEphemeralBlockDevices(data interface{}) ([]*spotinst.AwsGroupComputeBlockDevice, error) {
|
|
list := data.(*schema.Set).List()
|
|
devices := make([]*spotinst.AwsGroupComputeBlockDevice, 0, len(list))
|
|
for _, item := range list {
|
|
m := item.(map[string]interface{})
|
|
device := &spotinst.AwsGroupComputeBlockDevice{}
|
|
|
|
if v, ok := m["device_name"].(string); ok && v != "" {
|
|
device.DeviceName = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["virtual_name"].(string); ok && v != "" {
|
|
device.VirtualName = spotinst.String(v)
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup ephemeral block device configuration: %s\n", stringutil.Stringify(device))
|
|
devices = append(devices, device)
|
|
}
|
|
|
|
return devices, nil
|
|
}
|
|
|
|
// expandAwsGroupEBSBlockDevices expands the EBS Block Device block.
|
|
func expandAwsGroupEBSBlockDevices(data interface{}) ([]*spotinst.AwsGroupComputeBlockDevice, error) {
|
|
list := data.(*schema.Set).List()
|
|
devices := make([]*spotinst.AwsGroupComputeBlockDevice, 0, len(list))
|
|
for _, item := range list {
|
|
m := item.(map[string]interface{})
|
|
device := &spotinst.AwsGroupComputeBlockDevice{EBS: &spotinst.AwsGroupComputeEBS{}}
|
|
|
|
if v, ok := m["device_name"].(string); ok && v != "" {
|
|
device.DeviceName = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["delete_on_termination"].(bool); ok {
|
|
device.EBS.DeleteOnTermination = spotinst.Bool(v)
|
|
}
|
|
|
|
if v, ok := m["encrypted"].(bool); ok {
|
|
device.EBS.Encrypted = spotinst.Bool(v)
|
|
}
|
|
|
|
if v, ok := m["snapshot_id"].(string); ok && v != "" {
|
|
device.EBS.SnapshotID = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["volume_type"].(string); ok && v != "" {
|
|
device.EBS.VolumeType = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["volume_size"].(int); ok && v > 0 {
|
|
device.EBS.VolumeSize = spotinst.Int(v)
|
|
}
|
|
|
|
if v, ok := m["iops"].(int); ok && v > 0 {
|
|
device.EBS.IOPS = spotinst.Int(v)
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup elastic block device configuration: %s\n", stringutil.Stringify(device))
|
|
devices = append(devices, device)
|
|
}
|
|
|
|
return devices, nil
|
|
}
|
|
|
|
// iprofArnRE is a regular expression for matching IAM instance profile ARNs.
|
|
var iprofArnRE = regexp.MustCompile(`arn:aws:iam::\d{12}:instance-profile/?[a-zA-Z_0-9+=,.@\-_/]+`)
|
|
|
|
// expandAwsGroupLaunchSpecification expands the launch Specification block.
|
|
func expandAwsGroupLaunchSpecification(data interface{}) (*spotinst.AwsGroupComputeLaunchSpecification, error) {
|
|
list := data.(*schema.Set).List()
|
|
m := list[0].(map[string]interface{})
|
|
lc := &spotinst.AwsGroupComputeLaunchSpecification{}
|
|
|
|
if v, ok := m["monitoring"].(bool); ok {
|
|
lc.Monitoring = spotinst.Bool(v)
|
|
}
|
|
|
|
if v, ok := m["ebs_optimized"].(bool); ok {
|
|
lc.EBSOptimized = spotinst.Bool(v)
|
|
}
|
|
|
|
if v, ok := m["image_id"].(string); ok && v != "" {
|
|
lc.ImageID = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["key_pair"].(string); ok && v != "" {
|
|
lc.KeyPair = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["health_check_type"].(string); ok && v != "" {
|
|
lc.HealthCheckType = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["health_check_grace_period"].(int); ok && v > 0 {
|
|
lc.HealthCheckGracePeriod = spotinst.Int(v)
|
|
}
|
|
|
|
if v, ok := m["iam_instance_profile"].(string); ok && v != "" {
|
|
iprof := &spotinst.AwsGroupComputeIamInstanceProfile{}
|
|
if iprofArnRE.MatchString(v) {
|
|
iprof.Arn = spotinst.String(v)
|
|
} else {
|
|
iprof.Name = spotinst.String(v)
|
|
}
|
|
lc.IamInstanceProfile = iprof
|
|
}
|
|
|
|
if v, ok := m["user_data"].(string); ok && v != "" {
|
|
lc.UserData = spotinst.String(base64.StdEncoding.EncodeToString([]byte(v)))
|
|
}
|
|
|
|
if v, ok := m["security_group_ids"].([]interface{}); ok {
|
|
ids := make([]string, len(v))
|
|
for i, j := range v {
|
|
ids[i] = j.(string)
|
|
}
|
|
lc.SecurityGroupIDs = ids
|
|
}
|
|
|
|
if v, ok := m["load_balancer_names"].([]interface{}); ok {
|
|
var names []string
|
|
for _, j := range v {
|
|
if name, ok := j.(string); ok && name != "" {
|
|
names = append(names, name)
|
|
}
|
|
}
|
|
lc.LoadBalancerNames = names
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup launch specification configuration: %s\n", stringutil.Stringify(lc))
|
|
return lc, nil
|
|
}
|
|
|
|
// expandAwsGroupLoadBalancer expands the Load Balancer block.
|
|
func expandAwsGroupLoadBalancer(data interface{}) ([]*spotinst.AwsGroupComputeLoadBalancer, error) {
|
|
list := data.(*schema.Set).List()
|
|
lbs := make([]*spotinst.AwsGroupComputeLoadBalancer, 0, len(list))
|
|
for _, item := range list {
|
|
m := item.(map[string]interface{})
|
|
lb := &spotinst.AwsGroupComputeLoadBalancer{}
|
|
|
|
if v, ok := m["name"].(string); ok && v != "" {
|
|
lb.Name = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["arn"].(string); ok && v != "" {
|
|
lb.Arn = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["type"].(string); ok && v != "" {
|
|
lb.Type = spotinst.String(strings.ToUpper(v))
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup load balancer configuration: %s\n", stringutil.Stringify(lb))
|
|
lbs = append(lbs, lb)
|
|
}
|
|
|
|
return lbs, nil
|
|
}
|
|
|
|
// expandAwsGroupRancherIntegration expands the Rancher Integration block.
|
|
func expandAwsGroupRancherIntegration(data interface{}) (*spotinst.AwsGroupRancherIntegration, error) {
|
|
list := data.(*schema.Set).List()
|
|
m := list[0].(map[string]interface{})
|
|
i := &spotinst.AwsGroupRancherIntegration{}
|
|
|
|
if v, ok := m["master_host"].(string); ok && v != "" {
|
|
i.MasterHost = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["access_key"].(string); ok && v != "" {
|
|
i.AccessKey = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["secret_key"].(string); ok && v != "" {
|
|
i.SecretKey = spotinst.String(v)
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup Rancher integration configuration: %s\n", stringutil.Stringify(i))
|
|
return i, nil
|
|
}
|
|
|
|
// expandAwsGroupElasticBeanstalkIntegration expands the Elastic Beanstalk Integration block.
|
|
func expandAwsGroupElasticBeanstalkIntegration(data interface{}) (*spotinst.AwsGroupElasticBeanstalkIntegration, error) {
|
|
list := data.(*schema.Set).List()
|
|
m := list[0].(map[string]interface{})
|
|
i := &spotinst.AwsGroupElasticBeanstalkIntegration{}
|
|
|
|
if v, ok := m["environment_id"].(string); ok && v != "" {
|
|
i.EnvironmentID = spotinst.String(v)
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup Elastic Beanstalk integration configuration: %s\n", stringutil.Stringify(i))
|
|
return i, nil
|
|
}
|
|
|
|
// expandAwsGroupEC2ContainerServiceIntegration expands the EC2 Container Service Integration block.
|
|
func expandAwsGroupEC2ContainerServiceIntegration(data interface{}) (*spotinst.AwsGroupEC2ContainerServiceIntegration, error) {
|
|
list := data.(*schema.Set).List()
|
|
m := list[0].(map[string]interface{})
|
|
i := &spotinst.AwsGroupEC2ContainerServiceIntegration{}
|
|
|
|
if v, ok := m["cluster_name"].(string); ok && v != "" {
|
|
i.ClusterName = spotinst.String(v)
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup ECS integration configuration: %s\n", stringutil.Stringify(i))
|
|
return i, nil
|
|
}
|
|
|
|
// expandAwsGroupKubernetesIntegration expands the Kubernetes Integration block.
|
|
func expandAwsGroupKubernetesIntegration(data interface{}) (*spotinst.AwsGroupKubernetesIntegration, error) {
|
|
list := data.(*schema.Set).List()
|
|
m := list[0].(map[string]interface{})
|
|
i := &spotinst.AwsGroupKubernetesIntegration{}
|
|
|
|
if v, ok := m["api_server"].(string); ok && v != "" {
|
|
i.Server = spotinst.String(v)
|
|
}
|
|
|
|
if v, ok := m["token"].(string); ok && v != "" {
|
|
i.Token = spotinst.String(v)
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup Kubernetes integration configuration: %s\n", stringutil.Stringify(i))
|
|
return i, nil
|
|
}
|
|
|
|
// expandAwsGroupMesosphereIntegration expands the Mesosphere Integration block.
|
|
func expandAwsGroupMesosphereIntegration(data interface{}) (*spotinst.AwsGroupMesosphereIntegration, error) {
|
|
list := data.(*schema.Set).List()
|
|
m := list[0].(map[string]interface{})
|
|
i := &spotinst.AwsGroupMesosphereIntegration{}
|
|
|
|
if v, ok := m["api_server"].(string); ok && v != "" {
|
|
i.Server = spotinst.String(v)
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup Mesosphere integration configuration: %s\n", stringutil.Stringify(i))
|
|
return i, nil
|
|
}
|
|
|
|
// expandAwsGroupElasticIPs expands the Elastic IPs block.
|
|
func expandAwsGroupElasticIPs(data interface{}) ([]string, error) {
|
|
list := data.([]interface{})
|
|
eips := make([]string, 0, len(list))
|
|
for _, str := range list {
|
|
if eip, ok := str.(string); ok {
|
|
log.Printf("[DEBUG] AwsGroup elastic IP configuration: %s\n", stringutil.Stringify(eip))
|
|
eips = append(eips, eip)
|
|
}
|
|
}
|
|
|
|
return eips, nil
|
|
}
|
|
|
|
// expandAwsGroupTags expands the Tags block.
|
|
func expandAwsGroupTags(data interface{}) ([]*spotinst.AwsGroupComputeTag, error) {
|
|
list := data.(map[string]interface{})
|
|
tags := make([]*spotinst.AwsGroupComputeTag, 0, len(list))
|
|
for k, v := range list {
|
|
tag := &spotinst.AwsGroupComputeTag{
|
|
Key: spotinst.String(k),
|
|
Value: spotinst.String(v.(string)),
|
|
}
|
|
|
|
log.Printf("[DEBUG] AwsGroup tag configuration: %s\n", stringutil.Stringify(tag))
|
|
tags = append(tags, tag)
|
|
}
|
|
|
|
return tags, nil
|
|
}
|
|
|
|
func hashAwsGroupCapacity(v interface{}) int {
|
|
var buf bytes.Buffer
|
|
m := v.(map[string]interface{})
|
|
|
|
buf.WriteString(fmt.Sprintf("%d-", m["target"].(int)))
|
|
buf.WriteString(fmt.Sprintf("%d-", m["minimum"].(int)))
|
|
buf.WriteString(fmt.Sprintf("%d-", m["maximum"].(int)))
|
|
|
|
return hashcode.String(buf.String())
|
|
}
|
|
|
|
func hashAwsGroupStrategy(v interface{}) int {
|
|
var buf bytes.Buffer
|
|
m := v.(map[string]interface{})
|
|
|
|
buf.WriteString(fmt.Sprintf("%f-", m["risk"].(float64)))
|
|
buf.WriteString(fmt.Sprintf("%d-", m["ondemand_count"].(int)))
|
|
buf.WriteString(fmt.Sprintf("%t-", m["utilize_reserved_instances"].(bool)))
|
|
buf.WriteString(fmt.Sprintf("%t-", m["fallback_to_ondemand"].(bool)))
|
|
|
|
return hashcode.String(buf.String())
|
|
}
|
|
|
|
func hashAwsGroupLoadBalancer(v interface{}) int {
|
|
var buf bytes.Buffer
|
|
m := v.(map[string]interface{})
|
|
|
|
buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
|
|
buf.WriteString(fmt.Sprintf("%s-", m["type"].(string)))
|
|
if v, ok := m["arn"].(string); ok && len(v) > 0 {
|
|
buf.WriteString(fmt.Sprintf("%s-", v))
|
|
}
|
|
|
|
return hashcode.String(buf.String())
|
|
}
|
|
|
|
func hashAwsGroupEBSBlockDevice(v interface{}) int {
|
|
var buf bytes.Buffer
|
|
m := v.(map[string]interface{})
|
|
|
|
buf.WriteString(fmt.Sprintf("%s-", m["device_name"].(string)))
|
|
buf.WriteString(fmt.Sprintf("%s-", m["snapshot_id"].(string)))
|
|
buf.WriteString(fmt.Sprintf("%d-", m["volume_size"].(int)))
|
|
buf.WriteString(fmt.Sprintf("%t-", m["delete_on_termination"].(bool)))
|
|
buf.WriteString(fmt.Sprintf("%t-", m["encrypted"].(bool)))
|
|
buf.WriteString(fmt.Sprintf("%d-", m["iops"].(int)))
|
|
|
|
return hashcode.String(buf.String())
|
|
}
|
|
|
|
func hashAwsGroupScalingPolicy(v interface{}) int {
|
|
var buf bytes.Buffer
|
|
m := v.(map[string]interface{})
|
|
|
|
buf.WriteString(fmt.Sprintf("%d-", m["adjustment"].(int)))
|
|
buf.WriteString(fmt.Sprintf("%d-", m["cooldown"].(int)))
|
|
buf.WriteString(fmt.Sprintf("%d-", m["evaluation_periods"].(int)))
|
|
buf.WriteString(fmt.Sprintf("%s-", m["metric_name"].(string)))
|
|
buf.WriteString(fmt.Sprintf("%s-", m["namespace"].(string)))
|
|
buf.WriteString(fmt.Sprintf("%d-", m["period"].(int)))
|
|
buf.WriteString(fmt.Sprintf("%s-", m["policy_name"].(string)))
|
|
buf.WriteString(fmt.Sprintf("%s-", m["statistic"].(string)))
|
|
buf.WriteString(fmt.Sprintf("%f-", m["threshold"].(float64)))
|
|
buf.WriteString(fmt.Sprintf("%s-", m["unit"].(string)))
|
|
buf.WriteString(fmt.Sprintf("%d-", m["min_target_capacity"].(int)))
|
|
buf.WriteString(fmt.Sprintf("%d-", m["max_target_capacity"].(int)))
|
|
|
|
// if v, ok := m["operator"].(string); ok && len(v) > 0 {
|
|
// buf.WriteString(fmt.Sprintf("%s-", v))
|
|
// }
|
|
|
|
if d, ok := m["dimensions"]; ok {
|
|
if len(d.(map[string]interface{})) > 0 {
|
|
e := d.(map[string]interface{})
|
|
for k, v := range e {
|
|
buf.WriteString(fmt.Sprintf("%s:%s-", k, v.(string)))
|
|
}
|
|
}
|
|
}
|
|
|
|
return hashcode.String(buf.String())
|
|
}
|
|
|
|
// tagsToMap turns the list of tags into a map.
|
|
func tagsToMap(ts []*spotinst.AwsGroupComputeTag) map[string]string {
|
|
result := make(map[string]string)
|
|
for _, t := range ts {
|
|
result[spotinst.StringValue(t.Key)] = spotinst.StringValue(t.Value)
|
|
}
|
|
return result
|
|
}
|