From e5eed2f3e8b53af978e938d3f82937211fa2dd69 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 21 Sep 2018 19:51:30 -0400 Subject: [PATCH 1/2] New Resource: aws_ec2_fleet --- aws/provider.go | 1 + aws/resource_aws_ec2_fleet.go | 839 ++++++++++++ aws/resource_aws_ec2_fleet_test.go | 1698 ++++++++++++++++++++++++ website/aws.erb | 4 + website/docs/r/ec2_fleet.html.markdown | 104 ++ 5 files changed, 2646 insertions(+) create mode 100644 aws/resource_aws_ec2_fleet.go create mode 100644 aws/resource_aws_ec2_fleet_test.go create mode 100644 website/docs/r/ec2_fleet.html.markdown diff --git a/aws/provider.go b/aws/provider.go index 8c00f501dd7..187db702214 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -396,6 +396,7 @@ func Provider() terraform.ResourceProvider { "aws_dynamodb_table": resourceAwsDynamoDbTable(), "aws_dynamodb_table_item": resourceAwsDynamoDbTableItem(), "aws_dynamodb_global_table": resourceAwsDynamoDbGlobalTable(), + "aws_ec2_fleet": resourceAwsEc2Fleet(), "aws_ebs_snapshot": resourceAwsEbsSnapshot(), "aws_ebs_volume": resourceAwsEbsVolume(), "aws_ecr_lifecycle_policy": resourceAwsEcrLifecyclePolicy(), diff --git a/aws/resource_aws_ec2_fleet.go b/aws/resource_aws_ec2_fleet.go new file mode 100644 index 00000000000..5568f9769d9 --- /dev/null +++ b/aws/resource_aws_ec2_fleet.go @@ -0,0 +1,839 @@ +package aws + +import ( + "fmt" + "log" + "strconv" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" +) + +func resourceAwsEc2Fleet() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsEc2FleetCreate, + Read: resourceAwsEc2FleetRead, + Update: resourceAwsEc2FleetUpdate, + Delete: resourceAwsEc2FleetDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "excess_capacity_termination_policy": { + Type: schema.TypeString, + Optional: true, + Default: ec2.FleetExcessCapacityTerminationPolicyTermination, + ValidateFunc: validation.StringInSlice([]string{ + ec2.FleetExcessCapacityTerminationPolicyNoTermination, + ec2.FleetExcessCapacityTerminationPolicyTermination, + }, false), + }, + "launch_template_configs": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "launch_template_specification": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "launch_template_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "launch_template_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "version": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + }, + }, + "overrides": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 50, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "availability_zone": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "instance_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "max_price": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "priority": { + Type: schema.TypeFloat, + Optional: true, + ForceNew: true, + }, + "subnet_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "weighted_capacity": { + Type: schema.TypeFloat, + Optional: true, + ForceNew: true, + }, + }, + }, + }, + }, + }, + }, + "on_demand_options": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if old == "1" && new == "0" { + return true + } + return false + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allocation_strategy": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: "lowestPrice", + ValidateFunc: validation.StringInSlice([]string{ + // AWS SDK constant incorrect + // ec2.FleetOnDemandAllocationStrategyLowestPrice, + "lowestPrice", + ec2.FleetOnDemandAllocationStrategyPrioritized, + }, false), + }, + }, + }, + }, + "replace_unhealthy_instances": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + }, + "spot_options": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if old == "1" && new == "0" { + return true + } + return false + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allocation_strategy": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: "lowestPrice", + ValidateFunc: validation.StringInSlice([]string{ + ec2.SpotAllocationStrategyDiversified, + // AWS SDK constant incorrect + // ec2.SpotAllocationStrategyLowestPrice, + "lowestPrice", + }, false), + }, + "instance_interruption_behavior": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: ec2.SpotInstanceInterruptionBehaviorTerminate, + ValidateFunc: validation.StringInSlice([]string{ + ec2.SpotInstanceInterruptionBehaviorHibernate, + ec2.SpotInstanceInterruptionBehaviorStop, + ec2.SpotInstanceInterruptionBehaviorTerminate, + }, false), + }, + "instance_pools_to_use_count": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Default: 1, + ValidateFunc: validation.IntAtLeast(1), + }, + }, + }, + }, + "tags": { + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "target_capacity_specification": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default_target_capacity_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + ec2.DefaultTargetCapacityTypeOnDemand, + ec2.DefaultTargetCapacityTypeSpot, + }, false), + }, + "on_demand_target_capacity": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // Show difference for new resources + if d.Id() == "" { + return false + } + // Show difference if value is configured + if new != "0" { + return false + } + // Show difference if existing state reflects different default type + defaultTargetCapacityTypeO, _ := d.GetChange("target_capacity_specification.0.default_target_capacity_type") + if defaultTargetCapacityTypeO.(string) != ec2.DefaultTargetCapacityTypeOnDemand { + return false + } + // Show difference if existing state reflects different total capacity + oldInt, err := strconv.Atoi(old) + if err != nil { + log.Printf("[WARN] %s DiffSuppressFunc error converting %s to integer: %s", k, old, err) + return false + } + totalTargetCapacityO, _ := d.GetChange("target_capacity_specification.0.total_target_capacity") + if oldInt != totalTargetCapacityO.(int) { + return false + } + return true + }, + }, + "spot_target_capacity": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // Show difference for new resources + if d.Id() == "" { + return false + } + // Show difference if value is configured + if new != "0" { + return false + } + // Show difference if existing state reflects different default type + defaultTargetCapacityTypeO, _ := d.GetChange("target_capacity_specification.0.default_target_capacity_type") + if defaultTargetCapacityTypeO.(string) != ec2.DefaultTargetCapacityTypeSpot { + return false + } + // Show difference if existing state reflects different total capacity + oldInt, err := strconv.Atoi(old) + if err != nil { + log.Printf("[WARN] %s DiffSuppressFunc error converting %s to integer: %s", k, old, err) + return false + } + totalTargetCapacityO, _ := d.GetChange("target_capacity_specification.0.total_target_capacity") + if oldInt != totalTargetCapacityO.(int) { + return false + } + return true + }, + }, + "total_target_capacity": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + "terminate_instances": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "terminate_instances_with_expiration": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + }, + "type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: ec2.FleetTypeMaintain, + ValidateFunc: validation.StringInSlice([]string{ + ec2.FleetTypeMaintain, + ec2.FleetTypeRequest, + }, false), + }, + }, + } +} + +func resourceAwsEc2FleetCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + input := &ec2.CreateFleetInput{ + ExcessCapacityTerminationPolicy: aws.String(d.Get("excess_capacity_termination_policy").(string)), + LaunchTemplateConfigs: expandEc2FleetLaunchTemplateConfigRequests(d.Get("launch_template_configs").([]interface{})), + OnDemandOptions: expandEc2OnDemandOptionsRequest(d.Get("on_demand_options").([]interface{})), + ReplaceUnhealthyInstances: aws.Bool(d.Get("replace_unhealthy_instances").(bool)), + SpotOptions: expandEc2SpotOptionsRequest(d.Get("spot_options").([]interface{})), + TargetCapacitySpecification: expandEc2TargetCapacitySpecificationRequest(d.Get("target_capacity_specification").([]interface{})), + TerminateInstancesWithExpiration: aws.Bool(d.Get("terminate_instances_with_expiration").(bool)), + TagSpecifications: expandEc2TagSpecifications(d.Get("tags").(map[string]interface{})), + Type: aws.String(d.Get("type").(string)), + } + + log.Printf("[DEBUG] Creating EC2 Fleet: %s", input) + output, err := conn.CreateFleet(input) + if err != nil { + return fmt.Errorf("error creating EC2 Fleet: %s", err) + } + + d.SetId(aws.StringValue(output.FleetId)) + + // If a request type is fulfilled immediately, we can miss the transition from active to deleted + // Instead of an error here, allow the Read function to trigger recreation + target := []string{ec2.FleetStateCodeActive} + if d.Get("type").(string) == ec2.FleetTypeRequest { + target = append(target, ec2.FleetStateCodeDeleted) + target = append(target, ec2.FleetStateCodeDeletedRunning) + target = append(target, ec2.FleetStateCodeDeletedTerminating) + // AWS SDK constants incorrect + target = append(target, "deleted_running") + target = append(target, "deleted_terminating") + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{ec2.FleetStateCodeSubmitted}, + Target: target, + Refresh: ec2FleetRefreshFunc(conn, d.Id()), + Timeout: d.Timeout(schema.TimeoutCreate), + } + + log.Printf("[DEBUG] Waiting for EC2 Fleet (%s) activation", d.Id()) + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf("error waiting for EC2 Fleet (%s) activation: %s", d.Id(), err) + } + + return resourceAwsEc2FleetRead(d, meta) +} + +func resourceAwsEc2FleetRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + input := &ec2.DescribeFleetsInput{ + FleetIds: []*string{aws.String(d.Id())}, + } + + log.Printf("[DEBUG] Reading EC2 Fleet (%s): %s", d.Id(), input) + output, err := conn.DescribeFleets(input) + + if isAWSErr(err, "InvalidFleetId.NotFound", "") { + log.Printf("[WARN] EC2 Fleet (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading EC2 Fleet: %s", err) + } + + if output == nil || len(output.Fleets) == 0 { + log.Printf("[WARN] EC2 Fleet (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + var fleet *ec2.FleetData + for _, fleetData := range output.Fleets { + if fleetData == nil { + continue + } + if aws.StringValue(fleetData.FleetId) != d.Id() { + continue + } + fleet = fleetData + break + } + + if fleet == nil { + log.Printf("[WARN] EC2 Fleet (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + deletedStates := []string{ + ec2.FleetStateCodeDeleted, + ec2.FleetStateCodeDeletedRunning, + ec2.FleetStateCodeDeletedTerminating, + // AWS SDK constants are incorrect + "deleted_running", + "deleted_terminating", + } + for _, deletedState := range deletedStates { + if aws.StringValue(fleet.FleetState) == deletedState { + log.Printf("[WARN] EC2 Fleet (%s) in deleted state (%s), removing from state", d.Id(), aws.StringValue(fleet.FleetState)) + d.SetId("") + return nil + } + } + + d.Set("excess_capacity_termination_policy", fleet.ExcessCapacityTerminationPolicy) + + if err := d.Set("launch_template_configs", flattenEc2FleetLaunchTemplateConfigs(fleet.LaunchTemplateConfigs)); err != nil { + return fmt.Errorf("error setting launch_template_configs: %s", err) + } + + if err := d.Set("on_demand_options", flattenEc2OnDemandOptions(fleet.OnDemandOptions)); err != nil { + return fmt.Errorf("error setting on_demand_options: %s", err) + } + + d.Set("replace_unhealthy_instances", fleet.ReplaceUnhealthyInstances) + + if err := d.Set("spot_options", flattenEc2SpotOptions(fleet.SpotOptions)); err != nil { + return fmt.Errorf("error setting spot_options: %s", err) + } + + if err := d.Set("target_capacity_specification", flattenEc2TargetCapacitySpecification(fleet.TargetCapacitySpecification)); err != nil { + return fmt.Errorf("error setting target_capacity_specification: %s", err) + } + + d.Set("terminate_instances_with_expiration", fleet.TerminateInstancesWithExpiration) + d.Set("type", fleet.Type) + + if err := d.Set("tags", tagsToMap(fleet.Tags)); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + return nil +} + +func resourceAwsEc2FleetUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + input := &ec2.ModifyFleetInput{ + ExcessCapacityTerminationPolicy: aws.String(d.Get("excess_capacity_termination_policy").(string)), + FleetId: aws.String(d.Id()), + // InvalidTargetCapacitySpecification: Currently we only support total target capacity modification. + // TargetCapacitySpecification: expandEc2TargetCapacitySpecificationRequest(d.Get("target_capacity_specification").([]interface{})), + TargetCapacitySpecification: &ec2.TargetCapacitySpecificationRequest{ + TotalTargetCapacity: aws.Int64(int64(d.Get("target_capacity_specification.0.total_target_capacity").(int))), + }, + } + + log.Printf("[DEBUG] Modifying EC2 Fleet (%s): %s", d.Id(), input) + _, err := conn.ModifyFleet(input) + + if err != nil { + return fmt.Errorf("error modifying EC2 Fleet: %s", err) + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{ec2.FleetStateCodeModifying}, + Target: []string{ec2.FleetStateCodeActive}, + Refresh: ec2FleetRefreshFunc(conn, d.Id()), + Timeout: d.Timeout(schema.TimeoutUpdate), + } + + log.Printf("[DEBUG] Waiting for EC2 Fleet (%s) modification", d.Id()) + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf("error waiting for EC2 Fleet (%s) modification: %s", d.Id(), err) + } + + return resourceAwsEc2FleetRead(d, meta) +} + +func resourceAwsEc2FleetDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ec2conn + + input := &ec2.DeleteFleetsInput{ + FleetIds: []*string{aws.String(d.Id())}, + TerminateInstances: aws.Bool(d.Get("terminate_instances").(bool)), + } + + log.Printf("[DEBUG] Deleting EC2 Fleet (%s): %s", d.Id(), input) + _, err := conn.DeleteFleets(input) + + if isAWSErr(err, "InvalidFleetId.NotFound", "") { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting EC2 Fleet: %s", err) + } + + pending := []string{ec2.FleetStateCodeActive} + target := []string{ec2.FleetStateCodeDeleted} + if d.Get("terminate_instances").(bool) { + pending = append(pending, ec2.FleetStateCodeDeletedTerminating) + // AWS SDK constant is incorrect: unexpected state 'deleted_terminating', wanted target 'deleted, deleted-terminating' + pending = append(pending, "deleted_terminating") + } else { + target = append(target, ec2.FleetStateCodeDeletedRunning) + // AWS SDK constant is incorrect: unexpected state 'deleted_running', wanted target 'deleted, deleted-running' + target = append(target, "deleted_running") + } + + stateConf := &resource.StateChangeConf{ + Pending: pending, + Target: target, + Refresh: ec2FleetRefreshFunc(conn, d.Id()), + Timeout: d.Timeout(schema.TimeoutDelete), + } + + log.Printf("[DEBUG] Waiting for EC2 Fleet (%s) deletion", d.Id()) + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf("error waiting for EC2 Fleet (%s) deletion: %s", d.Id(), err) + } + + return nil +} + +func ec2FleetRefreshFunc(conn *ec2.EC2, fleetID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + input := &ec2.DescribeFleetsInput{ + FleetIds: []*string{aws.String(fleetID)}, + } + + log.Printf("[DEBUG] Reading EC2 Fleet (%s): %s", fleetID, input) + output, err := conn.DescribeFleets(input) + + if isAWSErr(err, "InvalidFleetId.NotFound", "") { + return nil, ec2.FleetStateCodeDeleted, nil + } + + if err != nil { + return nil, "", fmt.Errorf("error reading EC2 Fleet: %s", err) + } + + if output == nil || len(output.Fleets) == 0 { + return nil, ec2.FleetStateCodeDeleted, nil + } + + var fleet *ec2.FleetData + for _, fleetData := range output.Fleets { + if fleetData == nil { + continue + } + if aws.StringValue(fleetData.FleetId) == fleetID { + fleet = fleetData + } + } + + if fleet == nil { + return nil, ec2.FleetStateCodeDeleted, nil + } + + return fleet, aws.StringValue(fleet.FleetState), nil + } +} + +func expandEc2FleetLaunchTemplateConfigRequests(l []interface{}) []*ec2.FleetLaunchTemplateConfigRequest { + fleetLaunchTemplateConfigRequests := make([]*ec2.FleetLaunchTemplateConfigRequest, len(l)) + for i, m := range l { + if m == nil { + fleetLaunchTemplateConfigRequests[i] = &ec2.FleetLaunchTemplateConfigRequest{} + continue + } + + fleetLaunchTemplateConfigRequests[i] = expandEc2FleetLaunchTemplateConfigRequest(m.(map[string]interface{})) + } + return fleetLaunchTemplateConfigRequests +} + +func expandEc2FleetLaunchTemplateConfigRequest(m map[string]interface{}) *ec2.FleetLaunchTemplateConfigRequest { + fleetLaunchTemplateConfigRequest := &ec2.FleetLaunchTemplateConfigRequest{ + LaunchTemplateSpecification: expandEc2LaunchTemplateSpecificationRequest(m["launch_template_specification"].([]interface{})), + } + + if v, ok := m["overrides"]; ok { + fleetLaunchTemplateConfigRequest.Overrides = expandEc2FleetLaunchTemplateOverridesRequests(v.([]interface{})) + } + + return fleetLaunchTemplateConfigRequest +} + +func expandEc2FleetLaunchTemplateOverridesRequests(l []interface{}) []*ec2.FleetLaunchTemplateOverridesRequest { + if len(l) == 0 { + return nil + } + + fleetLaunchTemplateOverridesRequests := make([]*ec2.FleetLaunchTemplateOverridesRequest, len(l)) + for i, m := range l { + if m == nil { + fleetLaunchTemplateOverridesRequests[i] = &ec2.FleetLaunchTemplateOverridesRequest{} + continue + } + + fleetLaunchTemplateOverridesRequests[i] = expandEc2FleetLaunchTemplateOverridesRequest(m.(map[string]interface{})) + } + return fleetLaunchTemplateOverridesRequests +} + +func expandEc2FleetLaunchTemplateOverridesRequest(m map[string]interface{}) *ec2.FleetLaunchTemplateOverridesRequest { + fleetLaunchTemplateOverridesRequest := &ec2.FleetLaunchTemplateOverridesRequest{} + + if v, ok := m["availability_zone"]; ok && v.(string) != "" { + fleetLaunchTemplateOverridesRequest.AvailabilityZone = aws.String(v.(string)) + } + + if v, ok := m["instance_type"]; ok && v.(string) != "" { + fleetLaunchTemplateOverridesRequest.InstanceType = aws.String(v.(string)) + } + + if v, ok := m["max_price"]; ok && v.(string) != "" { + fleetLaunchTemplateOverridesRequest.MaxPrice = aws.String(v.(string)) + } + + if v, ok := m["priority"]; ok && v.(float64) != 0.0 { + fleetLaunchTemplateOverridesRequest.Priority = aws.Float64(v.(float64)) + } + + if v, ok := m["subnet_id"]; ok && v.(string) != "" { + fleetLaunchTemplateOverridesRequest.SubnetId = aws.String(v.(string)) + } + + if v, ok := m["weighted_capacity"]; ok && v.(float64) != 0.0 { + fleetLaunchTemplateOverridesRequest.WeightedCapacity = aws.Float64(v.(float64)) + } + + return fleetLaunchTemplateOverridesRequest +} + +func expandEc2LaunchTemplateSpecificationRequest(l []interface{}) *ec2.FleetLaunchTemplateSpecificationRequest { + fleetLaunchTemplateSpecificationRequest := &ec2.FleetLaunchTemplateSpecificationRequest{} + + if len(l) == 0 || l[0] == nil { + return fleetLaunchTemplateSpecificationRequest + } + + m := l[0].(map[string]interface{}) + + if v, ok := m["launch_template_id"]; ok && v.(string) != "" { + fleetLaunchTemplateSpecificationRequest.LaunchTemplateId = aws.String(v.(string)) + } + + if v, ok := m["launch_template_name"]; ok && v.(string) != "" { + fleetLaunchTemplateSpecificationRequest.LaunchTemplateName = aws.String(v.(string)) + } + + if v, ok := m["version"]; ok && v.(string) != "" { + fleetLaunchTemplateSpecificationRequest.Version = aws.String(v.(string)) + } + + return fleetLaunchTemplateSpecificationRequest +} + +func expandEc2OnDemandOptionsRequest(l []interface{}) *ec2.OnDemandOptionsRequest { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + return &ec2.OnDemandOptionsRequest{ + AllocationStrategy: aws.String(m["allocation_strategy"].(string)), + } +} + +func expandEc2SpotOptionsRequest(l []interface{}) *ec2.SpotOptionsRequest { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + spotOptionsRequest := &ec2.SpotOptionsRequest{ + AllocationStrategy: aws.String(m["allocation_strategy"].(string)), + InstanceInterruptionBehavior: aws.String(m["instance_interruption_behavior"].(string)), + } + + // InvalidFleetConfig: InstancePoolsToUseCount option is only available with the lowestPrice allocation strategy. + if aws.StringValue(spotOptionsRequest.AllocationStrategy) == "lowestPrice" { + spotOptionsRequest.InstancePoolsToUseCount = aws.Int64(int64(m["instance_pools_to_use_count"].(int))) + } + + return spotOptionsRequest +} + +func expandEc2TagSpecifications(m map[string]interface{}) []*ec2.TagSpecification { + if len(m) == 0 { + return nil + } + + return []*ec2.TagSpecification{ + { + ResourceType: aws.String("fleet"), + Tags: tagsFromMap(m), + }, + } +} + +func expandEc2TargetCapacitySpecificationRequest(l []interface{}) *ec2.TargetCapacitySpecificationRequest { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + targetCapacitySpecificationrequest := &ec2.TargetCapacitySpecificationRequest{ + TotalTargetCapacity: aws.Int64(int64(m["total_target_capacity"].(int))), + } + + if v, ok := m["default_target_capacity_type"]; ok && v.(string) != "" { + targetCapacitySpecificationrequest.DefaultTargetCapacityType = aws.String(v.(string)) + } + + if v, ok := m["on_demand_target_capacity"]; ok && v.(int) != 0 { + targetCapacitySpecificationrequest.OnDemandTargetCapacity = aws.Int64(int64(v.(int))) + } + + if v, ok := m["spot_target_capacity"]; ok && v.(int) != 0 { + targetCapacitySpecificationrequest.SpotTargetCapacity = aws.Int64(int64(v.(int))) + } + + return targetCapacitySpecificationrequest +} + +func flattenEc2FleetLaunchTemplateConfigs(fleetLaunchTemplateConfigs []*ec2.FleetLaunchTemplateConfig) []interface{} { + l := make([]interface{}, len(fleetLaunchTemplateConfigs)) + + for i, fleetLaunchTemplateConfig := range fleetLaunchTemplateConfigs { + if fleetLaunchTemplateConfig == nil { + l[i] = map[string]interface{}{} + continue + } + m := map[string]interface{}{ + "launch_template_specification": flattenEc2FleetLaunchTemplateSpecification(fleetLaunchTemplateConfig.LaunchTemplateSpecification), + "overrides": flattenEc2FleetLaunchTemplateOverrides(fleetLaunchTemplateConfig.Overrides), + } + l[i] = m + } + + return l +} + +func flattenEc2FleetLaunchTemplateOverrides(fleetLaunchTemplateOverrides []*ec2.FleetLaunchTemplateOverrides) []interface{} { + l := make([]interface{}, len(fleetLaunchTemplateOverrides)) + + for i, fleetLaunchTemplateOverride := range fleetLaunchTemplateOverrides { + if fleetLaunchTemplateOverride == nil { + l[i] = map[string]interface{}{} + continue + } + m := map[string]interface{}{ + "availability_zone": aws.StringValue(fleetLaunchTemplateOverride.AvailabilityZone), + "instance_type": aws.StringValue(fleetLaunchTemplateOverride.InstanceType), + "max_price": aws.StringValue(fleetLaunchTemplateOverride.MaxPrice), + "priority": aws.Float64Value(fleetLaunchTemplateOverride.Priority), + "subnet_id": aws.StringValue(fleetLaunchTemplateOverride.SubnetId), + "weighted_capacity": aws.Float64Value(fleetLaunchTemplateOverride.WeightedCapacity), + } + l[i] = m + } + + return l +} + +func flattenEc2FleetLaunchTemplateSpecification(fleetLaunchTemplateSpecification *ec2.FleetLaunchTemplateSpecification) []interface{} { + if fleetLaunchTemplateSpecification == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "launch_template_id": aws.StringValue(fleetLaunchTemplateSpecification.LaunchTemplateId), + "launch_template_name": aws.StringValue(fleetLaunchTemplateSpecification.LaunchTemplateName), + "version": aws.StringValue(fleetLaunchTemplateSpecification.Version), + } + + return []interface{}{m} +} + +func flattenEc2OnDemandOptions(onDemandOptions *ec2.OnDemandOptions) []interface{} { + if onDemandOptions == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "allocation_strategy": aws.StringValue(onDemandOptions.AllocationStrategy), + } + + return []interface{}{m} +} + +func flattenEc2SpotOptions(spotOptions *ec2.SpotOptions) []interface{} { + if spotOptions == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "allocation_strategy": aws.StringValue(spotOptions.AllocationStrategy), + "instance_interruption_behavior": aws.StringValue(spotOptions.InstanceInterruptionBehavior), + "instance_pools_to_use_count": aws.Int64Value(spotOptions.InstancePoolsToUseCount), + } + + // API will omit InstancePoolsToUseCount if AllocationStrategy is diversified, which breaks our Default: 1 + // Here we just reset it to 1 to prevent removing the Default and setting up a special DiffSuppressFunc + if spotOptions.InstancePoolsToUseCount == nil && aws.StringValue(spotOptions.AllocationStrategy) == ec2.SpotAllocationStrategyDiversified { + m["instance_pools_to_use_count"] = 1 + } + + return []interface{}{m} +} + +func flattenEc2TargetCapacitySpecification(targetCapacitySpecification *ec2.TargetCapacitySpecification) []interface{} { + if targetCapacitySpecification == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "default_target_capacity_type": aws.StringValue(targetCapacitySpecification.DefaultTargetCapacityType), + "on_demand_target_capacity": aws.Int64Value(targetCapacitySpecification.OnDemandTargetCapacity), + "spot_target_capacity": aws.Int64Value(targetCapacitySpecification.SpotTargetCapacity), + "total_target_capacity": aws.Int64Value(targetCapacitySpecification.TotalTargetCapacity), + } + + return []interface{}{m} +} diff --git a/aws/resource_aws_ec2_fleet_test.go b/aws/resource_aws_ec2_fleet_test.go new file mode 100644 index 00000000000..bb24090f404 --- /dev/null +++ b/aws/resource_aws_ec2_fleet_test.go @@ -0,0 +1,1698 @@ +package aws + +import ( + "errors" + "fmt" + "strconv" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAWSEc2Fleet_basic(t *testing.T) { + var fleet1 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_TargetCapacitySpecification_DefaultTargetCapacityType(rName, "spot"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "excess_capacity_termination_policy", "termination"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.launch_template_specification.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "launch_template_configs.0.launch_template_specification.0.launch_template_id"), + resource.TestCheckResourceAttrSet(resourceName, "launch_template_configs.0.launch_template_specification.0.version"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "0"), + resource.TestCheckResourceAttr(resourceName, "on_demand_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "on_demand_options.0.allocation_strategy", "lowestPrice"), + resource.TestCheckResourceAttr(resourceName, "replace_unhealthy_instances", "false"), + resource.TestCheckResourceAttr(resourceName, "spot_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spot_options.0.allocation_strategy", "lowestPrice"), + resource.TestCheckResourceAttr(resourceName, "spot_options.0.instance_interruption_behavior", "terminate"), + resource.TestCheckResourceAttr(resourceName, "spot_options.0.instance_pools_to_use_count", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "target_capacity_specification.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_capacity_specification.0.default_target_capacity_type", "spot"), + resource.TestCheckResourceAttr(resourceName, "target_capacity_specification.0.total_target_capacity", "0"), + resource.TestCheckResourceAttr(resourceName, "terminate_instances", "false"), + resource.TestCheckResourceAttr(resourceName, "terminate_instances_with_expiration", "false"), + resource.TestCheckResourceAttr(resourceName, "type", "maintain"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + }, + }) +} + +func TestAccAWSEc2Fleet_disappears(t *testing.T) { + var fleet1 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_TargetCapacitySpecification_DefaultTargetCapacityType(rName, "spot"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + testAccCheckAWSEc2FleetDisappears(&fleet1), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSEc2Fleet_ExcessCapacityTerminationPolicy(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_ExcessCapacityTerminationPolicy(rName, "no-termination"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "excess_capacity_termination_policy", "no-termination"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_ExcessCapacityTerminationPolicy(rName, "termination"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet2), + testAccCheckAWSEc2FleetNotRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "excess_capacity_termination_policy", "termination"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_LaunchTemplateConfigs_LaunchTemplateSpecification_LaunchTemplateId(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + launchTemplateResourceName1 := "aws_launch_template.test1" + launchTemplateResourceName2 := "aws_launch_template.test2" + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_LaunchTemplateId(rName, launchTemplateResourceName1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.launch_template_specification.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.launch_template_id", launchTemplateResourceName1, "id"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.version", launchTemplateResourceName1, "latest_version"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_LaunchTemplateId(rName, launchTemplateResourceName2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.launch_template_specification.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.launch_template_id", launchTemplateResourceName2, "id"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.version", launchTemplateResourceName2, "latest_version"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_LaunchTemplateConfigs_LaunchTemplateSpecification_LaunchTemplateName(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + launchTemplateResourceName1 := "aws_launch_template.test1" + launchTemplateResourceName2 := "aws_launch_template.test2" + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_LaunchTemplateName(rName, launchTemplateResourceName1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.launch_template_specification.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.launch_template_name", launchTemplateResourceName1, "name"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.version", launchTemplateResourceName1, "latest_version"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_LaunchTemplateName(rName, launchTemplateResourceName2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.launch_template_specification.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.launch_template_name", launchTemplateResourceName2, "name"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.version", launchTemplateResourceName2, "latest_version"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_LaunchTemplateConfigs_LaunchTemplateSpecification_Version(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + var launchTemplate ec2.LaunchTemplate + launchTemplateResourceName := "aws_launch_template.test" + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_Version(rName, "t3.micro"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLaunchTemplateExists(launchTemplateResourceName, &launchTemplate), + resource.TestCheckResourceAttr(launchTemplateResourceName, "instance_type", "t3.micro"), + resource.TestCheckResourceAttr(launchTemplateResourceName, "latest_version", "1"), + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.launch_template_specification.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.launch_template_id", launchTemplateResourceName, "id"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.version", launchTemplateResourceName, "latest_version"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_Version(rName, "t3.small"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSLaunchTemplateExists(launchTemplateResourceName, &launchTemplate), + resource.TestCheckResourceAttr(launchTemplateResourceName, "instance_type", "t3.small"), + resource.TestCheckResourceAttr(launchTemplateResourceName, "latest_version", "2"), + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.launch_template_specification.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.launch_template_id", launchTemplateResourceName, "id"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.version", launchTemplateResourceName, "latest_version"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_AvailabilityZone(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + availabilityZonesDataSourceName := "data.aws_availability_zones.available" + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_AvailabilityZone(rName, 0), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.overrides.0.availability_zone", availabilityZonesDataSourceName, "names.0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_AvailabilityZone(rName, 1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.overrides.0.availability_zone", availabilityZonesDataSourceName, "names.1"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_InstanceType(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_InstanceType(rName, "t3.small"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.instance_type", "t3.small"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_InstanceType(rName, "t3.medium"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.instance_type", "t3.medium"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_MaxPrice(t *testing.T) { + t.Skip("EC2 API is not correctly returning MaxPrice overrides") + + var fleet1, fleet2 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_MaxPrice(rName, "1.01"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.max_price", "1.01"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_MaxPrice(rName, "1.02"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.max_price", "1.02"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_Priority(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_Priority(rName, 1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.priority", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_Priority(rName, 2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.priority", "2"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_Priority_Multiple(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_Priority_Multiple(rName, 1, 2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "2"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.priority", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.1.priority", "2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_Priority_Multiple(rName, 2, 1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "2"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.priority", "2"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.1.priority", "1"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_SubnetId(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + subnetResourceName1 := "aws_subnet.test.0" + subnetResourceName2 := "aws_subnet.test.1" + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_SubnetId(rName, 0), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.overrides.0.subnet_id", subnetResourceName1, "id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_SubnetId(rName, 1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.overrides.0.subnet_id", subnetResourceName2, "id"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_WeightedCapacity(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_WeightedCapacity(rName, 1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.weighted_capacity", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_WeightedCapacity(rName, 2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.weighted_capacity", "2"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_WeightedCapacity_Multiple(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_WeightedCapacity_Multiple(rName, 1, 1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "2"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.weighted_capacity", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.1.weighted_capacity", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_WeightedCapacity_Multiple(rName, 1, 2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "2"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.weighted_capacity", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.1.weighted_capacity", "2"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_OnDemandOptions_AllocationStrategy(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_OnDemandOptions_AllocationStrategy(rName, "prioritized"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "on_demand_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "on_demand_options.0.allocation_strategy", "prioritized"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_OnDemandOptions_AllocationStrategy(rName, "lowestPrice"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet2), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "on_demand_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "on_demand_options.0.allocation_strategy", "lowestPrice"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_ReplaceUnhealthyInstances(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_ReplaceUnhealthyInstances(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "replace_unhealthy_instances", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_ReplaceUnhealthyInstances(rName, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet2), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "replace_unhealthy_instances", "false"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_SpotOptions_AllocationStrategy(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_SpotOptions_AllocationStrategy(rName, "diversified"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "spot_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spot_options.0.allocation_strategy", "diversified"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_SpotOptions_AllocationStrategy(rName, "lowestPrice"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet2), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "spot_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spot_options.0.allocation_strategy", "lowestPrice"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_SpotOptions_InstanceInterruptionBehavior(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_SpotOptions_InstanceInterruptionBehavior(rName, "stop"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "spot_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spot_options.0.instance_interruption_behavior", "stop"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_SpotOptions_InstanceInterruptionBehavior(rName, "terminate"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet2), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "spot_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spot_options.0.instance_interruption_behavior", "terminate"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_SpotOptions_InstancePoolsToUseCount(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_SpotOptions_InstancePoolsToUseCount(rName, 2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "spot_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spot_options.0.instance_pools_to_use_count", "2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_SpotOptions_InstancePoolsToUseCount(rName, 3), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet2), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "spot_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spot_options.0.instance_pools_to_use_count", "3"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_Tags(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_Tags(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_Tags(rName, "key1", "value1updated"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet2), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_TargetCapacitySpecification_DefaultTargetCapacityType(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_TargetCapacitySpecification_DefaultTargetCapacityType(rName, "on-demand"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "target_capacity_specification.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_capacity_specification.0.default_target_capacity_type", "on-demand"), + ), + }, + { + Config: testAccAWSEc2FleetConfig_TargetCapacitySpecification_DefaultTargetCapacityType(rName, "spot"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet2), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "target_capacity_specification.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_capacity_specification.0.default_target_capacity_type", "spot"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_TargetCapacitySpecification_DefaultTargetCapacityType_OnDemand(t *testing.T) { + var fleet1 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_TargetCapacitySpecification_DefaultTargetCapacityType(rName, "on-demand"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "target_capacity_specification.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_capacity_specification.0.default_target_capacity_type", "on-demand"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + }, + }) +} + +func TestAccAWSEc2Fleet_TargetCapacitySpecification_DefaultTargetCapacityType_Spot(t *testing.T) { + var fleet1 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_TargetCapacitySpecification_DefaultTargetCapacityType(rName, "spot"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "target_capacity_specification.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_capacity_specification.0.default_target_capacity_type", "spot"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + }, + }) +} + +func TestAccAWSEc2Fleet_TargetCapacitySpecification_TotalTargetCapacity(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_TargetCapacitySpecification_TotalTargetCapacity(rName, 1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "target_capacity_specification.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_capacity_specification.0.total_target_capacity", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_TargetCapacitySpecification_TotalTargetCapacity(rName, 2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet2), + testAccCheckAWSEc2FleetNotRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "target_capacity_specification.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_capacity_specification.0.total_target_capacity", "2"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_TerminateInstancesWithExpiration(t *testing.T) { + var fleet1, fleet2 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_TerminateInstancesWithExpiration(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "terminate_instances_with_expiration", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + { + Config: testAccAWSEc2FleetConfig_TerminateInstancesWithExpiration(rName, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet2), + testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + resource.TestCheckResourceAttr(resourceName, "terminate_instances_with_expiration", "false"), + ), + }, + }, + }) +} + +func TestAccAWSEc2Fleet_Type(t *testing.T) { + var fleet1 ec2.FleetData + resourceName := "aws_ec2_fleet.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEc2FleetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEc2FleetConfig_Type(rName, "maintain"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEc2FleetExists(resourceName, &fleet1), + resource.TestCheckResourceAttr(resourceName, "type", "maintain"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"terminate_instances"}, + }, + // This configuration will fulfill immediately, skip until ValidFrom is implemented + // { + // Config: testAccAWSEc2FleetConfig_Type(rName, "request"), + // Check: resource.ComposeTestCheckFunc( + // testAccCheckAWSEc2FleetExists(resourceName, &fleet2), + // testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), + // resource.TestCheckResourceAttr(resourceName, "type", "request"), + // ), + // }, + }, + }) +} + +func testAccCheckAWSEc2FleetExists(resourceName string, fleet *ec2.FleetData) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No EC2 Fleet ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).ec2conn + + input := &ec2.DescribeFleetsInput{ + FleetIds: []*string{aws.String(rs.Primary.ID)}, + } + + output, err := conn.DescribeFleets(input) + + if err != nil { + return err + } + + if output == nil { + return fmt.Errorf("EC2 Fleet not found") + } + + for _, fleetData := range output.Fleets { + if fleetData == nil { + continue + } + if aws.StringValue(fleetData.FleetId) != rs.Primary.ID { + continue + } + *fleet = *fleetData + break + } + + if fleet == nil { + return fmt.Errorf("EC2 Fleet not found") + } + + return nil + } +} + +func testAccCheckAWSEc2FleetDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).ec2conn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_ec2_fleet" { + continue + } + + input := &ec2.DescribeFleetsInput{ + FleetIds: []*string{aws.String(rs.Primary.ID)}, + } + + output, err := conn.DescribeFleets(input) + + if isAWSErr(err, "InvalidFleetId.NotFound", "") { + continue + } + + if err != nil { + return err + } + + if output == nil { + continue + } + + for _, fleetData := range output.Fleets { + if fleetData == nil { + continue + } + if aws.StringValue(fleetData.FleetId) != rs.Primary.ID { + continue + } + if aws.StringValue(fleetData.FleetState) == ec2.FleetStateCodeDeleted { + break + } + terminateInstances, err := strconv.ParseBool(rs.Primary.Attributes["terminate_instances"]) + if err != nil { + return fmt.Errorf("error converting terminate_instances (%s) to bool: %s", rs.Primary.Attributes["terminate_instances"], err) + } + if !terminateInstances && aws.StringValue(fleetData.FleetState) == ec2.FleetStateCodeDeletedRunning { + break + } + // AWS SDK constant is incorrect + if !terminateInstances && aws.StringValue(fleetData.FleetState) == "deleted_running" { + break + } + return fmt.Errorf("EC2 Fleet (%s) still exists in non-deleted (%s) state", rs.Primary.ID, aws.StringValue(fleetData.FleetState)) + } + } + + return nil +} + +func testAccCheckAWSEc2FleetDisappears(fleet *ec2.FleetData) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).ec2conn + + input := &ec2.DeleteFleetsInput{ + FleetIds: []*string{fleet.FleetId}, + TerminateInstances: aws.Bool(false), + } + + _, err := conn.DeleteFleets(input) + + return err + } +} + +func testAccCheckAWSEc2FleetNotRecreated(i, j *ec2.FleetData) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.TimeValue(i.CreateTime) != aws.TimeValue(j.CreateTime) { + return errors.New("EC2 Fleet was recreated") + } + + return nil + } +} + +func testAccCheckAWSEc2FleetRecreated(i, j *ec2.FleetData) resource.TestCheckFunc { + return func(s *terraform.State) error { + if aws.TimeValue(i.CreateTime) == aws.TimeValue(j.CreateTime) { + return errors.New("EC2 Fleet was not recreated") + } + + return nil + } +} + +func testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName string) string { + return fmt.Sprintf(` +data "aws_ami" "test" { + most_recent = true + owners = ["amazon"] + + filter { + name = "name" + values = ["amzn-ami-hvm-*-x86_64-gp2"] + } +} + +resource "aws_launch_template" "test" { + image_id = "${data.aws_ami.test.id}" + instance_type = "t3.micro" + name = %q +} +`, rName) +} + +func testAccAWSEc2FleetConfig_ExcessCapacityTerminationPolicy(rName, excessCapacityTerminationPolicy string) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + excess_capacity_termination_policy = %q + + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, excessCapacityTerminationPolicy) +} + +func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_LaunchTemplateId(rName, launchTemplateResourceName string) string { + return fmt.Sprintf(` +data "aws_ami" "test" { + most_recent = true + owners = ["amazon"] + + filter { + name = "name" + values = ["amzn-ami-hvm-*-x86_64-gp2"] + } +} + +resource "aws_launch_template" "test1" { + image_id = "${data.aws_ami.test.id}" + instance_type = "t3.micro" + name = "%s1" +} + +resource "aws_launch_template" "test2" { + image_id = "${data.aws_ami.test.id}" + instance_type = "t3.micro" + name = "%s2" +} + +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${%s.id}" + version = "${%s.latest_version}" + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, rName, rName, launchTemplateResourceName, launchTemplateResourceName) +} + +func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_LaunchTemplateName(rName, launchTemplateResourceName string) string { + return fmt.Sprintf(` +data "aws_ami" "test" { + most_recent = true + owners = ["amazon"] + + filter { + name = "name" + values = ["amzn-ami-hvm-*-x86_64-gp2"] + } +} + +resource "aws_launch_template" "test1" { + image_id = "${data.aws_ami.test.id}" + instance_type = "t3.micro" + name = "%s1" +} + +resource "aws_launch_template" "test2" { + image_id = "${data.aws_ami.test.id}" + instance_type = "t3.micro" + name = "%s2" +} + +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_name = "${%s.name}" + version = "${%s.latest_version}" + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, rName, rName, launchTemplateResourceName, launchTemplateResourceName) +} + +func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_Version(rName, instanceType string) string { + return fmt.Sprintf(` +data "aws_ami" "test" { + most_recent = true + owners = ["amazon"] + + filter { + name = "name" + values = ["amzn-ami-hvm-*-x86_64-gp2"] + } +} + +resource "aws_launch_template" "test" { + image_id = "${data.aws_ami.test.id}" + instance_type = %q + name = %q +} + +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, instanceType, rName) +} + +func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_AvailabilityZone(rName string, availabilityZoneIndex int) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +data "aws_availability_zones" "available" {} + +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + + overrides { + availability_zone = "${data.aws_availability_zones.available.names[%d]}" + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, availabilityZoneIndex) +} + +func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_InstanceType(rName, instanceType string) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + + overrides { + instance_type = %q + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, instanceType) +} + +func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_MaxPrice(rName, maxPrice string) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + + overrides { + max_price = %q + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, maxPrice) +} + +func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_Priority(rName string, priority int) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + + overrides { + priority = %d + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, priority) +} + +func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_Priority_Multiple(rName string, priority1, priority2 int) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + + overrides { + instance_type = "${aws_launch_template.test.instance_type}" + priority = %d + } + + overrides { + instance_type = "t3.small" + priority = %d + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, priority1, priority2) +} + +func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_SubnetId(rName string, subnetIndex int) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +variable "TestAccNameTag" { + default = "tf-acc-test-ec2-fleet-launchtemplateconfig-overrides-subnetid" +} + +resource "aws_vpc" "test" { + cidr_block = "10.1.0.0/16" + + tags { + Name = "${var.TestAccNameTag}" + } +} + +resource "aws_subnet" "test" { + count = 2 + + cidr_block = "10.1.${count.index}.0/24" + vpc_id = "${aws_vpc.test.id}" + + tags { + Name = "${var.TestAccNameTag}" + } +} + +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + + overrides { + subnet_id = "${aws_subnet.test.*.id[%d]}" + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, subnetIndex) +} + +func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_WeightedCapacity(rName string, weightedCapacity int) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + + overrides { + weighted_capacity = %d + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, weightedCapacity) +} + +func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_WeightedCapacity_Multiple(rName string, weightedCapacity1, weightedCapacity2 int) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + + overrides { + instance_type = "${aws_launch_template.test.instance_type}" + weighted_capacity = %d + } + + overrides { + instance_type = "t3.small" + weighted_capacity = %d + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, weightedCapacity1, weightedCapacity2) +} + +func testAccAWSEc2FleetConfig_OnDemandOptions_AllocationStrategy(rName, allocationStrategy string) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + } + + on_demand_options { + allocation_strategy = %q + } + + target_capacity_specification { + default_target_capacity_type = "on-demand" + total_target_capacity = 0 + } +} +`, allocationStrategy) +} + +func testAccAWSEc2FleetConfig_ReplaceUnhealthyInstances(rName string, replaceUnhealthyInstances bool) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + replace_unhealthy_instances = %t + + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, replaceUnhealthyInstances) +} + +func testAccAWSEc2FleetConfig_SpotOptions_AllocationStrategy(rName, allocationStrategy string) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + } + + spot_options { + allocation_strategy = %q + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, allocationStrategy) +} + +func testAccAWSEc2FleetConfig_SpotOptions_InstanceInterruptionBehavior(rName, instanceInterruptionBehavior string) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + } + + spot_options { + instance_interruption_behavior = %q + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, instanceInterruptionBehavior) +} + +func testAccAWSEc2FleetConfig_SpotOptions_InstancePoolsToUseCount(rName string, instancePoolsToUseCount int) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + } + + spot_options { + instance_pools_to_use_count = %d + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, instancePoolsToUseCount) +} + +func testAccAWSEc2FleetConfig_Tags(rName, key1, value1 string) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + } + + tags { + %q = %q + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, key1, value1) +} + +func testAccAWSEc2FleetConfig_TargetCapacitySpecification_DefaultTargetCapacityType(rName, defaultTargetCapacityType string) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + } + + target_capacity_specification { + default_target_capacity_type = %q + total_target_capacity = 0 + } +} +`, defaultTargetCapacityType) +} + +func testAccAWSEc2FleetConfig_TargetCapacitySpecification_TotalTargetCapacity(rName string, totalTargetCapacity int) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + terminate_instances = true + + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = %d + } +} +`, totalTargetCapacity) +} + +func testAccAWSEc2FleetConfig_TerminateInstancesWithExpiration(rName string, terminateInstancesWithExpiration bool) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + terminate_instances_with_expiration = %t + + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, terminateInstancesWithExpiration) +} + +func testAccAWSEc2FleetConfig_Type(rName, fleetType string) string { + return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` +resource "aws_ec2_fleet" "test" { + type = %q + + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.test.id}" + version = "${aws_launch_template.test.latest_version}" + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 0 + } +} +`, fleetType) +} diff --git a/website/aws.erb b/website/aws.erb index 1797d92bdb9..b580ab536f8 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -962,6 +962,10 @@ aws_ebs_volume + > + aws_ec2_fleet + + > aws_eip diff --git a/website/docs/r/ec2_fleet.html.markdown b/website/docs/r/ec2_fleet.html.markdown new file mode 100644 index 00000000000..11a8c702c74 --- /dev/null +++ b/website/docs/r/ec2_fleet.html.markdown @@ -0,0 +1,104 @@ +--- +layout: "aws" +page_title: "AWS: aws_ec2_fleet" +sidebar_current: "docs-aws-resource-ec2-fleet" +description: |- + Provides a resource to manage EC2 Fleets +--- + +# aws_ec2_fleet + +Provides a resource to manage EC2 Fleets. + +## Example Usage + +```hcl +resource "aws_ec2_fleet" "example" { + launch_template_configs { + launch_template_specification { + launch_template_id = "${aws_launch_template.example.id}" + version = "${aws_launch_template.example.latest_version}" + } + } + + target_capacity_specification { + default_target_capacity_type = "spot" + total_target_capacity = 5 + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `launch_template_configs` - (Required) Nested argument containing EC2 Launch Template configurations. Defined below. +* `target_capacity_specification` - (Required) Nested argument containing target capacity configurations. Defined below. +* `excess_capacity_termination_policy` - (Optional) Whether running instances should be terminated if the total target capacity of the EC2 Fleet is decreased below the current size of the EC2. Valid values: `no-termination`, `termination`. Defaults to `termination`. +* `on_demand_options` - (Optional) Nested argument containing On-Demand configurations. Defined below. +* `replace_unhealthy_instances` - (Optional) Whether EC2 Fleet should replace unhealthy instances. Defaults to `false`. +* `spot_options` - (Optional) Nested argument containing Spot configurations. Defined below. +* `tags` - (Optional) Map of Fleet tags. To tag instances at launch, specify the tags in the Launch Template. +* `terminate_instances` - (Optional) Whether to terminate instances for an EC2 Fleet if it is deleted successfully. Defaults to `false`. +* `terminate_instances_with_expiration` - (Optional) Whether running instances should be terminated when the EC2 Fleet expires. Defaults to `false`. +* `type` - (Optional) The type of request. Indicates whether the EC2 Fleet only requests the target capacity, or also attempts to maintain it. Valid values: `maintain`, `request`. Defaults to `maintain`. + +### launch_template_configs + +* `launch_template_specification` - (Required) Nested argument containing EC2 Launch Template to use. Defined below. + +#### launch_template_specification + +~> *NOTE:* Either `launch_template_id` or `launch_template_name` must be specified. + +* `version` - (Required) Version number of the launch template. +* `launch_template_id` - (Optional) ID of the launch template. +* `launch_template_name` - (Optional) Name of the launch template. + +#### overrides + +* `availability_zone` - (Optional) Availability Zone in which to launch the instances. +* `instance_type` - (Optional) Instance type. +* `max_price` - (Optional) Maximum price per unit hour that you are willing to pay for a Spot Instance. +* `priority` - (Optional) Priority for the launch template override. If `on_demand_options` `allocation_strategy` is set to `prioritized`, EC2 Fleet uses priority to determine which launch template override to use first in fulfilling On-Demand capacity. The highest priority is launched first. The lower the number, the higher the priority. If no number is set, the launch template override has the lowest priority. Valid values are whole numbers starting at 0. +* `subnet_id` - (Optional) ID of the subnet in which to launch the instances. +* `weighted_capacity` - (Optional) Number of units provided by the specified instance type. + +### on_demand_options + +* `allocation_strategy` - (Optional) The order of the launch template overrides to use in fulfilling On-Demand capacity. Valid values: `lowestPrice`, `prioritized`. Default: `lowestPrice`. + +### spot_options + +* `allocation_strategy` - (Optional) How to allocate the target capacity across the Spot pools. Valid values: `diversified`, `lowestPrice`. Default: `lowestPrice`. +* `instance_interruption_behavior` - (Optional) Behavior when a Spot Instance is interrupted. Valid values: `hibernate`, `stop`, `terminate`. Default: `terminate`. +* `instance_pools_to_use_count` - (Optional) Number of Spot pools across which to allocate your target Spot capacity. Valid only when Spot `allocation_strategy` is set to `lowestPrice`. Default: `1`. + +### target_capacity_specification + +* `default_target_capacity_type` - (Required) Default target capacity type. Valid values: `on-demand`, `spot`. +* `total_target_capacity` - (Required) The number of units to request, filled using `default_target_capacity_type`. +* `on_demand_target_capacity` - (Optional) The number of On-Demand units to request. +* `spot_target_capacity` - (Optional) The number of Spot units to request. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - Fleet identifier + +## Timeouts + +`aws_ec2_fleet` provides the following [Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +* `create` - (Default `10m`) How long to wait for a fleet to be active. +* `update` - (Default `10m`) How long to wait for a fleet to be modified. +* `delete` - (Default `10m`) How long to wait for a fleet to be deleted. If `terminate_instances` is `true`, how long to wait for instances to terminate. + +## Import + +`aws_ec2_fleet` can be imported by using the Fleet identifier, e.g. + +``` +$ terraform import aws_ec2_fleet.example fleet-b9b55d27-c5fc-41ac-a6f3-48fcc91f080c +``` From 31a8f7107eee8c3723c701c7dfd2279ea485cde2 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 2 Oct 2018 21:27:46 -0400 Subject: [PATCH 2/2] resource/aws_ec2_fleet: Address PR #5960 feedback Output from acceptance testing: ``` --- PASS: TestAccAWSEc2Fleet_basic (35.71s) --- PASS: TestAccAWSEc2Fleet_disappears (32.21s) --- PASS: TestAccAWSEc2Fleet_ExcessCapacityTerminationPolicy (94.75s) --- PASS: TestAccAWSEc2Fleet_LaunchTemplateConfig_LaunchTemplateSpecification_LaunchTemplateId (72.23s) --- PASS: TestAccAWSEc2Fleet_LaunchTemplateConfig_LaunchTemplateSpecification_LaunchTemplateName (65.05s) --- PASS: TestAccAWSEc2Fleet_LaunchTemplateConfig_LaunchTemplateSpecification_Version (66.15s) --- PASS: TestAccAWSEc2Fleet_LaunchTemplateConfig_Override_AvailabilityZone (64.70s) --- PASS: TestAccAWSEc2Fleet_LaunchTemplateConfig_Override_InstanceType (70.11s) --- PASS: TestAccAWSEc2Fleet_LaunchTemplateConfig_Override_Priority (62.72s) --- PASS: TestAccAWSEc2Fleet_LaunchTemplateConfig_Override_Priority_Multiple (62.67s) --- PASS: TestAccAWSEc2Fleet_LaunchTemplateConfig_Override_SubnetId (84.59s) --- PASS: TestAccAWSEc2Fleet_LaunchTemplateConfig_Override_WeightedCapacity (66.18s) --- PASS: TestAccAWSEc2Fleet_LaunchTemplateConfig_Override_WeightedCapacity_Multiple (66.18s) --- PASS: TestAccAWSEc2Fleet_OnDemandOptions_AllocationStrategy (65.99s) --- PASS: TestAccAWSEc2Fleet_ReplaceUnhealthyInstances (67.76s) --- PASS: TestAccAWSEc2Fleet_SpotOptions_AllocationStrategy (65.17s) --- PASS: TestAccAWSEc2Fleet_SpotOptions_InstanceInterruptionBehavior (64.85s) --- PASS: TestAccAWSEc2Fleet_SpotOptions_InstancePoolsToUseCount (62.53s) --- PASS: TestAccAWSEc2Fleet_Tags (65.32s) --- PASS: TestAccAWSEc2Fleet_TargetCapacitySpecification_DefaultTargetCapacityType (64.69s) --- PASS: TestAccAWSEc2Fleet_TargetCapacitySpecification_DefaultTargetCapacityType_OnDemand (32.68s) --- PASS: TestAccAWSEc2Fleet_TargetCapacitySpecification_DefaultTargetCapacityType_Spot (34.97s) --- PASS: TestAccAWSEc2Fleet_TargetCapacitySpecification_TotalTargetCapacity (468.10s) --- PASS: TestAccAWSEc2Fleet_TerminateInstancesWithExpiration (63.03s) --- PASS: TestAccAWSEc2Fleet_Type (32.81s) ``` --- aws/resource_aws_ec2_fleet.go | 15 +- aws/resource_aws_ec2_fleet_test.go | 318 ++++++++++++------------- website/docs/r/ec2_fleet.html.markdown | 31 ++- 3 files changed, 194 insertions(+), 170 deletions(-) diff --git a/aws/resource_aws_ec2_fleet.go b/aws/resource_aws_ec2_fleet.go index 5568f9769d9..7e816cddef9 100644 --- a/aws/resource_aws_ec2_fleet.go +++ b/aws/resource_aws_ec2_fleet.go @@ -38,7 +38,7 @@ func resourceAwsEc2Fleet() *schema.Resource { ec2.FleetExcessCapacityTerminationPolicyTermination, }, false), }, - "launch_template_configs": { + "launch_template_config": { Type: schema.TypeList, Required: true, ForceNew: true, @@ -72,7 +72,7 @@ func resourceAwsEc2Fleet() *schema.Resource { }, }, }, - "overrides": { + "override": { Type: schema.TypeList, Optional: true, ForceNew: true, @@ -312,7 +312,7 @@ func resourceAwsEc2FleetCreate(d *schema.ResourceData, meta interface{}) error { input := &ec2.CreateFleetInput{ ExcessCapacityTerminationPolicy: aws.String(d.Get("excess_capacity_termination_policy").(string)), - LaunchTemplateConfigs: expandEc2FleetLaunchTemplateConfigRequests(d.Get("launch_template_configs").([]interface{})), + LaunchTemplateConfigs: expandEc2FleetLaunchTemplateConfigRequests(d.Get("launch_template_config").([]interface{})), OnDemandOptions: expandEc2OnDemandOptionsRequest(d.Get("on_demand_options").([]interface{})), ReplaceUnhealthyInstances: aws.Bool(d.Get("replace_unhealthy_instances").(bool)), SpotOptions: expandEc2SpotOptionsRequest(d.Get("spot_options").([]interface{})), @@ -420,8 +420,8 @@ func resourceAwsEc2FleetRead(d *schema.ResourceData, meta interface{}) error { d.Set("excess_capacity_termination_policy", fleet.ExcessCapacityTerminationPolicy) - if err := d.Set("launch_template_configs", flattenEc2FleetLaunchTemplateConfigs(fleet.LaunchTemplateConfigs)); err != nil { - return fmt.Errorf("error setting launch_template_configs: %s", err) + if err := d.Set("launch_template_config", flattenEc2FleetLaunchTemplateConfigs(fleet.LaunchTemplateConfigs)); err != nil { + return fmt.Errorf("error setting launch_template_config: %s", err) } if err := d.Set("on_demand_options", flattenEc2OnDemandOptions(fleet.OnDemandOptions)); err != nil { @@ -559,6 +559,7 @@ func ec2FleetRefreshFunc(conn *ec2.EC2, fleetID string) resource.StateRefreshFun } if aws.StringValue(fleetData.FleetId) == fleetID { fleet = fleetData + break } } @@ -588,7 +589,7 @@ func expandEc2FleetLaunchTemplateConfigRequest(m map[string]interface{}) *ec2.Fl LaunchTemplateSpecification: expandEc2LaunchTemplateSpecificationRequest(m["launch_template_specification"].([]interface{})), } - if v, ok := m["overrides"]; ok { + if v, ok := m["override"]; ok { fleetLaunchTemplateConfigRequest.Overrides = expandEc2FleetLaunchTemplateOverridesRequests(v.([]interface{})) } @@ -747,7 +748,7 @@ func flattenEc2FleetLaunchTemplateConfigs(fleetLaunchTemplateConfigs []*ec2.Flee } m := map[string]interface{}{ "launch_template_specification": flattenEc2FleetLaunchTemplateSpecification(fleetLaunchTemplateConfig.LaunchTemplateSpecification), - "overrides": flattenEc2FleetLaunchTemplateOverrides(fleetLaunchTemplateConfig.Overrides), + "override": flattenEc2FleetLaunchTemplateOverrides(fleetLaunchTemplateConfig.Overrides), } l[i] = m } diff --git a/aws/resource_aws_ec2_fleet_test.go b/aws/resource_aws_ec2_fleet_test.go index bb24090f404..61aa0111922 100644 --- a/aws/resource_aws_ec2_fleet_test.go +++ b/aws/resource_aws_ec2_fleet_test.go @@ -28,11 +28,11 @@ func TestAccAWSEc2Fleet_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), resource.TestCheckResourceAttr(resourceName, "excess_capacity_termination_policy", "termination"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.launch_template_specification.#", "1"), - resource.TestCheckResourceAttrSet(resourceName, "launch_template_configs.0.launch_template_specification.0.launch_template_id"), - resource.TestCheckResourceAttrSet(resourceName, "launch_template_configs.0.launch_template_specification.0.version"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "0"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.launch_template_specification.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "launch_template_config.0.launch_template_specification.0.launch_template_id"), + resource.TestCheckResourceAttrSet(resourceName, "launch_template_config.0.launch_template_specification.0.version"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "0"), resource.TestCheckResourceAttr(resourceName, "on_demand_options.#", "1"), resource.TestCheckResourceAttr(resourceName, "on_demand_options.0.allocation_strategy", "lowestPrice"), resource.TestCheckResourceAttr(resourceName, "replace_unhealthy_instances", "false"), @@ -116,7 +116,7 @@ func TestAccAWSEc2Fleet_ExcessCapacityTerminationPolicy(t *testing.T) { }) } -func TestAccAWSEc2Fleet_LaunchTemplateConfigs_LaunchTemplateSpecification_LaunchTemplateId(t *testing.T) { +func TestAccAWSEc2Fleet_LaunchTemplateConfig_LaunchTemplateSpecification_LaunchTemplateId(t *testing.T) { var fleet1, fleet2 ec2.FleetData launchTemplateResourceName1 := "aws_launch_template.test1" launchTemplateResourceName2 := "aws_launch_template.test2" @@ -129,13 +129,13 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_LaunchTemplateSpecification_Launch CheckDestroy: testAccCheckAWSEc2FleetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_LaunchTemplateId(rName, launchTemplateResourceName1), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_LaunchTemplateSpecification_LaunchTemplateId(rName, launchTemplateResourceName1), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.launch_template_specification.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.launch_template_id", launchTemplateResourceName1, "id"), - resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.version", launchTemplateResourceName1, "latest_version"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.launch_template_specification.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_config.0.launch_template_specification.0.launch_template_id", launchTemplateResourceName1, "id"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_config.0.launch_template_specification.0.version", launchTemplateResourceName1, "latest_version"), ), }, { @@ -145,21 +145,21 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_LaunchTemplateSpecification_Launch ImportStateVerifyIgnore: []string{"terminate_instances"}, }, { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_LaunchTemplateId(rName, launchTemplateResourceName2), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_LaunchTemplateSpecification_LaunchTemplateId(rName, launchTemplateResourceName2), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.launch_template_specification.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.launch_template_id", launchTemplateResourceName2, "id"), - resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.version", launchTemplateResourceName2, "latest_version"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.launch_template_specification.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_config.0.launch_template_specification.0.launch_template_id", launchTemplateResourceName2, "id"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_config.0.launch_template_specification.0.version", launchTemplateResourceName2, "latest_version"), ), }, }, }) } -func TestAccAWSEc2Fleet_LaunchTemplateConfigs_LaunchTemplateSpecification_LaunchTemplateName(t *testing.T) { +func TestAccAWSEc2Fleet_LaunchTemplateConfig_LaunchTemplateSpecification_LaunchTemplateName(t *testing.T) { var fleet1, fleet2 ec2.FleetData launchTemplateResourceName1 := "aws_launch_template.test1" launchTemplateResourceName2 := "aws_launch_template.test2" @@ -172,13 +172,13 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_LaunchTemplateSpecification_Launch CheckDestroy: testAccCheckAWSEc2FleetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_LaunchTemplateName(rName, launchTemplateResourceName1), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_LaunchTemplateSpecification_LaunchTemplateName(rName, launchTemplateResourceName1), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.launch_template_specification.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.launch_template_name", launchTemplateResourceName1, "name"), - resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.version", launchTemplateResourceName1, "latest_version"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.launch_template_specification.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_config.0.launch_template_specification.0.launch_template_name", launchTemplateResourceName1, "name"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_config.0.launch_template_specification.0.version", launchTemplateResourceName1, "latest_version"), ), }, { @@ -188,21 +188,21 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_LaunchTemplateSpecification_Launch ImportStateVerifyIgnore: []string{"terminate_instances"}, }, { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_LaunchTemplateName(rName, launchTemplateResourceName2), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_LaunchTemplateSpecification_LaunchTemplateName(rName, launchTemplateResourceName2), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.launch_template_specification.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.launch_template_name", launchTemplateResourceName2, "name"), - resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.version", launchTemplateResourceName2, "latest_version"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.launch_template_specification.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_config.0.launch_template_specification.0.launch_template_name", launchTemplateResourceName2, "name"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_config.0.launch_template_specification.0.version", launchTemplateResourceName2, "latest_version"), ), }, }, }) } -func TestAccAWSEc2Fleet_LaunchTemplateConfigs_LaunchTemplateSpecification_Version(t *testing.T) { +func TestAccAWSEc2Fleet_LaunchTemplateConfig_LaunchTemplateSpecification_Version(t *testing.T) { var fleet1, fleet2 ec2.FleetData var launchTemplate ec2.LaunchTemplate launchTemplateResourceName := "aws_launch_template.test" @@ -215,16 +215,16 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_LaunchTemplateSpecification_Versio CheckDestroy: testAccCheckAWSEc2FleetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_Version(rName, "t3.micro"), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_LaunchTemplateSpecification_Version(rName, "t3.micro"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLaunchTemplateExists(launchTemplateResourceName, &launchTemplate), resource.TestCheckResourceAttr(launchTemplateResourceName, "instance_type", "t3.micro"), resource.TestCheckResourceAttr(launchTemplateResourceName, "latest_version", "1"), testAccCheckAWSEc2FleetExists(resourceName, &fleet1), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.launch_template_specification.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.launch_template_id", launchTemplateResourceName, "id"), - resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.version", launchTemplateResourceName, "latest_version"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.launch_template_specification.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_config.0.launch_template_specification.0.launch_template_id", launchTemplateResourceName, "id"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_config.0.launch_template_specification.0.version", launchTemplateResourceName, "latest_version"), ), }, { @@ -234,24 +234,24 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_LaunchTemplateSpecification_Versio ImportStateVerifyIgnore: []string{"terminate_instances"}, }, { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_Version(rName, "t3.small"), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_LaunchTemplateSpecification_Version(rName, "t3.small"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSLaunchTemplateExists(launchTemplateResourceName, &launchTemplate), resource.TestCheckResourceAttr(launchTemplateResourceName, "instance_type", "t3.small"), resource.TestCheckResourceAttr(launchTemplateResourceName, "latest_version", "2"), testAccCheckAWSEc2FleetExists(resourceName, &fleet1), testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.launch_template_specification.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.launch_template_id", launchTemplateResourceName, "id"), - resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.launch_template_specification.0.version", launchTemplateResourceName, "latest_version"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.launch_template_specification.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_config.0.launch_template_specification.0.launch_template_id", launchTemplateResourceName, "id"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_config.0.launch_template_specification.0.version", launchTemplateResourceName, "latest_version"), ), }, }, }) } -func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_AvailabilityZone(t *testing.T) { +func TestAccAWSEc2Fleet_LaunchTemplateConfig_Override_AvailabilityZone(t *testing.T) { var fleet1, fleet2 ec2.FleetData availabilityZonesDataSourceName := "data.aws_availability_zones.available" resourceName := "aws_ec2_fleet.test" @@ -263,12 +263,12 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_AvailabilityZone(t *test CheckDestroy: testAccCheckAWSEc2FleetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_AvailabilityZone(rName, 0), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_AvailabilityZone(rName, 0), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.overrides.0.availability_zone", availabilityZonesDataSourceName, "names.0"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_config.0.override.0.availability_zone", availabilityZonesDataSourceName, "names.0"), ), }, { @@ -278,20 +278,20 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_AvailabilityZone(t *test ImportStateVerifyIgnore: []string{"terminate_instances"}, }, { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_AvailabilityZone(rName, 1), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_AvailabilityZone(rName, 1), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.overrides.0.availability_zone", availabilityZonesDataSourceName, "names.1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_config.0.override.0.availability_zone", availabilityZonesDataSourceName, "names.1"), ), }, }, }) } -func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_InstanceType(t *testing.T) { +func TestAccAWSEc2Fleet_LaunchTemplateConfig_Override_InstanceType(t *testing.T) { var fleet1, fleet2 ec2.FleetData resourceName := "aws_ec2_fleet.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -302,12 +302,12 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_InstanceType(t *testing. CheckDestroy: testAccCheckAWSEc2FleetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_InstanceType(rName, "t3.small"), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_InstanceType(rName, "t3.small"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.instance_type", "t3.small"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.0.instance_type", "t3.small"), ), }, { @@ -317,21 +317,21 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_InstanceType(t *testing. ImportStateVerifyIgnore: []string{"terminate_instances"}, }, { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_InstanceType(rName, "t3.medium"), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_InstanceType(rName, "t3.medium"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.instance_type", "t3.medium"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.0.instance_type", "t3.medium"), ), }, }, }) } -func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_MaxPrice(t *testing.T) { - t.Skip("EC2 API is not correctly returning MaxPrice overrides") +func TestAccAWSEc2Fleet_LaunchTemplateConfig_Override_MaxPrice(t *testing.T) { + t.Skip("EC2 API is not correctly returning MaxPrice override") var fleet1, fleet2 ec2.FleetData resourceName := "aws_ec2_fleet.test" @@ -343,12 +343,12 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_MaxPrice(t *testing.T) { CheckDestroy: testAccCheckAWSEc2FleetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_MaxPrice(rName, "1.01"), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_MaxPrice(rName, "1.01"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.max_price", "1.01"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.0.max_price", "1.01"), ), }, { @@ -358,20 +358,20 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_MaxPrice(t *testing.T) { ImportStateVerifyIgnore: []string{"terminate_instances"}, }, { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_MaxPrice(rName, "1.02"), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_MaxPrice(rName, "1.02"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.max_price", "1.02"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.0.max_price", "1.02"), ), }, }, }) } -func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_Priority(t *testing.T) { +func TestAccAWSEc2Fleet_LaunchTemplateConfig_Override_Priority(t *testing.T) { var fleet1, fleet2 ec2.FleetData resourceName := "aws_ec2_fleet.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -382,12 +382,12 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_Priority(t *testing.T) { CheckDestroy: testAccCheckAWSEc2FleetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_Priority(rName, 1), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_Priority(rName, 1), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.priority", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.0.priority", "1"), ), }, { @@ -397,20 +397,20 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_Priority(t *testing.T) { ImportStateVerifyIgnore: []string{"terminate_instances"}, }, { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_Priority(rName, 2), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_Priority(rName, 2), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.priority", "2"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.0.priority", "2"), ), }, }, }) } -func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_Priority_Multiple(t *testing.T) { +func TestAccAWSEc2Fleet_LaunchTemplateConfig_Override_Priority_Multiple(t *testing.T) { var fleet1, fleet2 ec2.FleetData resourceName := "aws_ec2_fleet.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -421,13 +421,13 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_Priority_Multiple(t *tes CheckDestroy: testAccCheckAWSEc2FleetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_Priority_Multiple(rName, 1, 2), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_Priority_Multiple(rName, 1, 2), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "2"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.priority", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.1.priority", "2"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "2"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.0.priority", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.1.priority", "2"), ), }, { @@ -437,21 +437,21 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_Priority_Multiple(t *tes ImportStateVerifyIgnore: []string{"terminate_instances"}, }, { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_Priority_Multiple(rName, 2, 1), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_Priority_Multiple(rName, 2, 1), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "2"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.priority", "2"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.1.priority", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "2"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.0.priority", "2"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.1.priority", "1"), ), }, }, }) } -func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_SubnetId(t *testing.T) { +func TestAccAWSEc2Fleet_LaunchTemplateConfig_Override_SubnetId(t *testing.T) { var fleet1, fleet2 ec2.FleetData subnetResourceName1 := "aws_subnet.test.0" subnetResourceName2 := "aws_subnet.test.1" @@ -464,12 +464,12 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_SubnetId(t *testing.T) { CheckDestroy: testAccCheckAWSEc2FleetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_SubnetId(rName, 0), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_SubnetId(rName, 0), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.overrides.0.subnet_id", subnetResourceName1, "id"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_config.0.override.0.subnet_id", subnetResourceName1, "id"), ), }, { @@ -479,20 +479,20 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_SubnetId(t *testing.T) { ImportStateVerifyIgnore: []string{"terminate_instances"}, }, { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_SubnetId(rName, 1), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_SubnetId(rName, 1), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "launch_template_configs.0.overrides.0.subnet_id", subnetResourceName2, "id"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "launch_template_config.0.override.0.subnet_id", subnetResourceName2, "id"), ), }, }, }) } -func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_WeightedCapacity(t *testing.T) { +func TestAccAWSEc2Fleet_LaunchTemplateConfig_Override_WeightedCapacity(t *testing.T) { var fleet1, fleet2 ec2.FleetData resourceName := "aws_ec2_fleet.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -503,12 +503,12 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_WeightedCapacity(t *test CheckDestroy: testAccCheckAWSEc2FleetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_WeightedCapacity(rName, 1), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_WeightedCapacity(rName, 1), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.weighted_capacity", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.0.weighted_capacity", "1"), ), }, { @@ -518,20 +518,20 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_WeightedCapacity(t *test ImportStateVerifyIgnore: []string{"terminate_instances"}, }, { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_WeightedCapacity(rName, 2), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_WeightedCapacity(rName, 2), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.weighted_capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.0.weighted_capacity", "2"), ), }, }, }) } -func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_WeightedCapacity_Multiple(t *testing.T) { +func TestAccAWSEc2Fleet_LaunchTemplateConfig_Override_WeightedCapacity_Multiple(t *testing.T) { var fleet1, fleet2 ec2.FleetData resourceName := "aws_ec2_fleet.test" rName := acctest.RandomWithPrefix("tf-acc-test") @@ -542,13 +542,13 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_WeightedCapacity_Multipl CheckDestroy: testAccCheckAWSEc2FleetDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_WeightedCapacity_Multiple(rName, 1, 1), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_WeightedCapacity_Multiple(rName, 1, 1), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "2"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.weighted_capacity", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.1.weighted_capacity", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "2"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.0.weighted_capacity", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.1.weighted_capacity", "1"), ), }, { @@ -558,14 +558,14 @@ func TestAccAWSEc2Fleet_LaunchTemplateConfigs_Overrides_WeightedCapacity_Multipl ImportStateVerifyIgnore: []string{"terminate_instances"}, }, { - Config: testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_WeightedCapacity_Multiple(rName, 1, 2), + Config: testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_WeightedCapacity_Multiple(rName, 1, 2), Check: resource.ComposeTestCheckFunc( testAccCheckAWSEc2FleetExists(resourceName, &fleet1), testAccCheckAWSEc2FleetRecreated(&fleet1, &fleet2), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.#", "2"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.0.weighted_capacity", "1"), - resource.TestCheckResourceAttr(resourceName, "launch_template_configs.0.overrides.1.weighted_capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.#", "2"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.0.weighted_capacity", "1"), + resource.TestCheckResourceAttr(resourceName, "launch_template_config.0.override.1.weighted_capacity", "2"), ), }, }, @@ -1147,7 +1147,7 @@ func testAccAWSEc2FleetConfig_ExcessCapacityTerminationPolicy(rName, excessCapac resource "aws_ec2_fleet" "test" { excess_capacity_termination_policy = %q - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" @@ -1162,7 +1162,7 @@ resource "aws_ec2_fleet" "test" { `, excessCapacityTerminationPolicy) } -func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_LaunchTemplateId(rName, launchTemplateResourceName string) string { +func testAccAWSEc2FleetConfig_LaunchTemplateConfig_LaunchTemplateSpecification_LaunchTemplateId(rName, launchTemplateResourceName string) string { return fmt.Sprintf(` data "aws_ami" "test" { most_recent = true @@ -1187,7 +1187,7 @@ resource "aws_launch_template" "test2" { } resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${%s.id}" version = "${%s.latest_version}" @@ -1202,7 +1202,7 @@ resource "aws_ec2_fleet" "test" { `, rName, rName, launchTemplateResourceName, launchTemplateResourceName) } -func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_LaunchTemplateName(rName, launchTemplateResourceName string) string { +func testAccAWSEc2FleetConfig_LaunchTemplateConfig_LaunchTemplateSpecification_LaunchTemplateName(rName, launchTemplateResourceName string) string { return fmt.Sprintf(` data "aws_ami" "test" { most_recent = true @@ -1227,7 +1227,7 @@ resource "aws_launch_template" "test2" { } resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_name = "${%s.name}" version = "${%s.latest_version}" @@ -1242,7 +1242,7 @@ resource "aws_ec2_fleet" "test" { `, rName, rName, launchTemplateResourceName, launchTemplateResourceName) } -func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_LaunchTemplateSpecification_Version(rName, instanceType string) string { +func testAccAWSEc2FleetConfig_LaunchTemplateConfig_LaunchTemplateSpecification_Version(rName, instanceType string) string { return fmt.Sprintf(` data "aws_ami" "test" { most_recent = true @@ -1261,7 +1261,7 @@ resource "aws_launch_template" "test" { } resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" @@ -1276,18 +1276,18 @@ resource "aws_ec2_fleet" "test" { `, instanceType, rName) } -func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_AvailabilityZone(rName string, availabilityZoneIndex int) string { +func testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_AvailabilityZone(rName string, availabilityZoneIndex int) string { return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` data "aws_availability_zones" "available" {} resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" } - overrides { + override { availability_zone = "${data.aws_availability_zones.available.names[%d]}" } } @@ -1300,16 +1300,16 @@ resource "aws_ec2_fleet" "test" { `, availabilityZoneIndex) } -func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_InstanceType(rName, instanceType string) string { +func testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_InstanceType(rName, instanceType string) string { return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" } - overrides { + override { instance_type = %q } } @@ -1322,16 +1322,16 @@ resource "aws_ec2_fleet" "test" { `, instanceType) } -func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_MaxPrice(rName, maxPrice string) string { +func testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_MaxPrice(rName, maxPrice string) string { return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" } - overrides { + override { max_price = %q } } @@ -1344,16 +1344,16 @@ resource "aws_ec2_fleet" "test" { `, maxPrice) } -func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_Priority(rName string, priority int) string { +func testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_Priority(rName string, priority int) string { return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" } - overrides { + override { priority = %d } } @@ -1366,21 +1366,21 @@ resource "aws_ec2_fleet" "test" { `, priority) } -func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_Priority_Multiple(rName string, priority1, priority2 int) string { +func testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_Priority_Multiple(rName string, priority1, priority2 int) string { return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" } - overrides { + override { instance_type = "${aws_launch_template.test.instance_type}" priority = %d } - overrides { + override { instance_type = "t3.small" priority = %d } @@ -1394,10 +1394,10 @@ resource "aws_ec2_fleet" "test" { `, priority1, priority2) } -func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_SubnetId(rName string, subnetIndex int) string { +func testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_SubnetId(rName string, subnetIndex int) string { return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` variable "TestAccNameTag" { - default = "tf-acc-test-ec2-fleet-launchtemplateconfig-overrides-subnetid" + default = "tf-acc-test-ec2-fleet-launchtemplateconfig-override-subnetid" } resource "aws_vpc" "test" { @@ -1420,13 +1420,13 @@ resource "aws_subnet" "test" { } resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" } - overrides { + override { subnet_id = "${aws_subnet.test.*.id[%d]}" } } @@ -1439,16 +1439,16 @@ resource "aws_ec2_fleet" "test" { `, subnetIndex) } -func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_WeightedCapacity(rName string, weightedCapacity int) string { +func testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_WeightedCapacity(rName string, weightedCapacity int) string { return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" } - overrides { + override { weighted_capacity = %d } } @@ -1461,21 +1461,21 @@ resource "aws_ec2_fleet" "test" { `, weightedCapacity) } -func testAccAWSEc2FleetConfig_LaunchTemplateConfigs_Overrides_WeightedCapacity_Multiple(rName string, weightedCapacity1, weightedCapacity2 int) string { +func testAccAWSEc2FleetConfig_LaunchTemplateConfig_Override_WeightedCapacity_Multiple(rName string, weightedCapacity1, weightedCapacity2 int) string { return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" } - overrides { + override { instance_type = "${aws_launch_template.test.instance_type}" weighted_capacity = %d } - overrides { + override { instance_type = "t3.small" weighted_capacity = %d } @@ -1492,7 +1492,7 @@ resource "aws_ec2_fleet" "test" { func testAccAWSEc2FleetConfig_OnDemandOptions_AllocationStrategy(rName, allocationStrategy string) string { return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" @@ -1516,7 +1516,7 @@ func testAccAWSEc2FleetConfig_ReplaceUnhealthyInstances(rName string, replaceUnh resource "aws_ec2_fleet" "test" { replace_unhealthy_instances = %t - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" @@ -1534,7 +1534,7 @@ resource "aws_ec2_fleet" "test" { func testAccAWSEc2FleetConfig_SpotOptions_AllocationStrategy(rName, allocationStrategy string) string { return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" @@ -1556,7 +1556,7 @@ resource "aws_ec2_fleet" "test" { func testAccAWSEc2FleetConfig_SpotOptions_InstanceInterruptionBehavior(rName, instanceInterruptionBehavior string) string { return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" @@ -1578,7 +1578,7 @@ resource "aws_ec2_fleet" "test" { func testAccAWSEc2FleetConfig_SpotOptions_InstancePoolsToUseCount(rName string, instancePoolsToUseCount int) string { return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" @@ -1600,7 +1600,7 @@ resource "aws_ec2_fleet" "test" { func testAccAWSEc2FleetConfig_Tags(rName, key1, value1 string) string { return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" @@ -1622,7 +1622,7 @@ resource "aws_ec2_fleet" "test" { func testAccAWSEc2FleetConfig_TargetCapacitySpecification_DefaultTargetCapacityType(rName, defaultTargetCapacityType string) string { return testAccAWSEc2FleetConfig_BaseLaunchTemplate(rName) + fmt.Sprintf(` resource "aws_ec2_fleet" "test" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" @@ -1642,7 +1642,7 @@ func testAccAWSEc2FleetConfig_TargetCapacitySpecification_TotalTargetCapacity(rN resource "aws_ec2_fleet" "test" { terminate_instances = true - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" @@ -1662,7 +1662,7 @@ func testAccAWSEc2FleetConfig_TerminateInstancesWithExpiration(rName string, ter resource "aws_ec2_fleet" "test" { terminate_instances_with_expiration = %t - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" @@ -1682,7 +1682,7 @@ func testAccAWSEc2FleetConfig_Type(rName, fleetType string) string { resource "aws_ec2_fleet" "test" { type = %q - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.test.id}" version = "${aws_launch_template.test.latest_version}" diff --git a/website/docs/r/ec2_fleet.html.markdown b/website/docs/r/ec2_fleet.html.markdown index 11a8c702c74..7ca899601b2 100644 --- a/website/docs/r/ec2_fleet.html.markdown +++ b/website/docs/r/ec2_fleet.html.markdown @@ -14,7 +14,7 @@ Provides a resource to manage EC2 Fleets. ```hcl resource "aws_ec2_fleet" "example" { - launch_template_configs { + launch_template_config { launch_template_specification { launch_template_id = "${aws_launch_template.example.id}" version = "${aws_launch_template.example.latest_version}" @@ -32,7 +32,7 @@ resource "aws_ec2_fleet" "example" { The following arguments are supported: -* `launch_template_configs` - (Required) Nested argument containing EC2 Launch Template configurations. Defined below. +* `launch_template_config` - (Required) Nested argument containing EC2 Launch Template configurations. Defined below. * `target_capacity_specification` - (Required) Nested argument containing target capacity configurations. Defined below. * `excess_capacity_termination_policy` - (Optional) Whether running instances should be terminated if the total target capacity of the EC2 Fleet is decreased below the current size of the EC2. Valid values: `no-termination`, `termination`. Defaults to `termination`. * `on_demand_options` - (Optional) Nested argument containing On-Demand configurations. Defined below. @@ -43,9 +43,10 @@ The following arguments are supported: * `terminate_instances_with_expiration` - (Optional) Whether running instances should be terminated when the EC2 Fleet expires. Defaults to `false`. * `type` - (Optional) The type of request. Indicates whether the EC2 Fleet only requests the target capacity, or also attempts to maintain it. Valid values: `maintain`, `request`. Defaults to `maintain`. -### launch_template_configs +### launch_template_config * `launch_template_specification` - (Required) Nested argument containing EC2 Launch Template to use. Defined below. +* `override` - (Optional) Nested argument(s) containing parameters to override the same parameters in the Launch Template. Defined below. #### launch_template_specification @@ -55,7 +56,29 @@ The following arguments are supported: * `launch_template_id` - (Optional) ID of the launch template. * `launch_template_name` - (Optional) Name of the launch template. -#### overrides +#### override + +Example: + +```hcl +resource "aws_ec2_fleet" "example" { + # ... other configuration ... + + launch_template_config { + # ... other configuration ... + + override { + instance_type = "m4.xlarge" + weighted_capacity = 1 + } + + override { + instance_type = "m4.2xlarge" + weighted_capacity = 2 + } + } +} +``` * `availability_zone` - (Optional) Availability Zone in which to launch the instances. * `instance_type` - (Optional) Instance type.