diff --git a/.changelog/24543.txt b/.changelog/24543.txt new file mode 100644 index 000000000000..e65cc2dd1818 --- /dev/null +++ b/.changelog/24543.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_launch_template: Add `instance_requirements` argument +``` + +```release-note:enhancement +data-source/aws_launch_template: Add `instance_requirements` attribute +``` \ No newline at end of file diff --git a/internal/service/ec2/ec2_launch_template.go b/internal/service/ec2/ec2_launch_template.go index ae29043ae65b..29f7b8cef748 100644 --- a/internal/service/ec2/ec2_launch_template.go +++ b/internal/service/ec2/ec2_launch_template.go @@ -338,9 +338,255 @@ func ResourceLaunchTemplate() *schema.Resource { }, }, }, - "instance_type": { - Type: schema.TypeString, + "instance_requirements": { + Type: schema.TypeList, Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "accelerator_count": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(0), + }, + "min": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(1), + }, + }, + }, + }, + "accelerator_manufacturers": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(ec2.AcceleratorManufacturer_Values(), false), + }, + }, + "accelerator_names": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(ec2.AcceleratorName_Values(), false), + }, + }, + "accelerator_total_memory_mib": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(1), + }, + "min": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(1), + }, + }, + }, + }, + "accelerator_types": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(ec2.AcceleratorType_Values(), false), + }, + }, + "bare_metal": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(ec2.BareMetal_Values(), false), + }, + "baseline_ebs_bandwidth_mbps": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(1), + }, + "min": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(1), + }, + }, + }, + }, + "burstable_performance": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(ec2.BurstablePerformance_Values(), false), + }, + "cpu_manufacturers": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(ec2.CpuManufacturer_Values(), false), + }, + }, + "excluded_instance_types": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 400, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "instance_generations": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(ec2.InstanceGeneration_Values(), false), + }, + }, + "local_storage": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(ec2.LocalStorage_Values(), false), + }, + "local_storage_types": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(ec2.LocalStorageType_Values(), false), + }, + }, + "memory_gib_per_vcpu": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeFloat, + Optional: true, + ValidateFunc: verify.FloatGreaterThan(0.0), + }, + "min": { + Type: schema.TypeFloat, + Optional: true, + ValidateFunc: verify.FloatGreaterThan(0.0), + }, + }, + }, + }, + "memory_mib": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(1), + }, + "min": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntAtLeast(1), + }, + }, + }, + }, + "network_interface_count": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(1), + }, + "min": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(1), + }, + }, + }, + }, + "on_demand_max_price_percentage_over_lowest_price": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(1), + }, + "require_hibernate_support": { + Type: schema.TypeBool, + Optional: true, + }, + "spot_max_price_percentage_over_lowest_price": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(1), + }, + "total_local_storage_gb": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeFloat, + Optional: true, + ValidateFunc: verify.FloatGreaterThan(0.0), + }, + "min": { + Type: schema.TypeFloat, + Optional: true, + ValidateFunc: verify.FloatGreaterThan(0.0), + }, + }, + }, + }, + "vcpu_count": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(1), + }, + "min": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntAtLeast(1), + }, + }, + }, + }, + }, + }, + ConflictsWith: []string{"instance_type"}, + }, + "instance_type": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"instance_requirements"}, }, "kernel_id": { Type: schema.TypeString, @@ -806,6 +1052,7 @@ func resourceLaunchTemplateUpdate(d *schema.ResourceData, meta interface{}) erro "image_id", "instance_initiated_shutdown_behavior", "instance_market_options", + "instance_requirements", "instance_type", "kernel_id", "key_name", @@ -972,6 +1219,10 @@ func expandRequestLaunchTemplateData(d *schema.ResourceData) *ec2.RequestLaunchT apiObject.InstanceMarketOptions = expandLaunchTemplateInstanceMarketOptionsRequest(v.([]interface{})[0].(map[string]interface{})) } + if v, ok := d.GetOk("instance_requirements"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + apiObject.InstanceRequirements = expandInstanceRequirementsRequest(v.([]interface{})[0].(map[string]interface{})) + } + if v, ok := d.GetOk("kernel_id"); ok { apiObject.KernelId = aws.String(v.(string)) } @@ -1281,6 +1532,244 @@ func expandLaunchTemplateInstanceMarketOptionsRequest(tfMap map[string]interface return apiObject } +func expandInstanceRequirementsRequest(tfMap map[string]interface{}) *ec2.InstanceRequirementsRequest { + if tfMap == nil { + return nil + } + + apiObject := &ec2.InstanceRequirementsRequest{} + + if v, ok := tfMap["accelerator_count"].([]interface{}); ok && len(v) > 0 { + apiObject.AcceleratorCount = expandAcceleratorCountRequest(v[0].(map[string]interface{})) + } + + if v, ok := tfMap["accelerator_manufacturers"].(*schema.Set); ok && v.Len() > 0 { + apiObject.AcceleratorManufacturers = flex.ExpandStringSet(v) + } + + if v, ok := tfMap["accelerator_names"].(*schema.Set); ok && v.Len() > 0 { + apiObject.AcceleratorNames = flex.ExpandStringSet(v) + } + + if v, ok := tfMap["accelerator_total_memory_mib"].([]interface{}); ok && len(v) > 0 { + apiObject.AcceleratorTotalMemoryMiB = expandAcceleratorTotalMemoryMiBRequest(v[0].(map[string]interface{})) + } + + if v, ok := tfMap["accelerator_types"].(*schema.Set); ok && v.Len() > 0 { + apiObject.AcceleratorTypes = flex.ExpandStringSet(v) + } + + if v, ok := tfMap["bare_metal"].(string); ok && v != "" { + apiObject.BareMetal = aws.String(v) + } + + if v, ok := tfMap["baseline_ebs_bandwidth_mbps"].([]interface{}); ok && len(v) > 0 { + apiObject.BaselineEbsBandwidthMbps = expandBaselineEbsBandwidthMbpsRequest(v[0].(map[string]interface{})) + } + + if v, ok := tfMap["burstable_performance"].(string); ok && v != "" { + apiObject.BurstablePerformance = aws.String(v) + } + + if v, ok := tfMap["cpu_manufacturers"].(*schema.Set); ok && v.Len() > 0 { + apiObject.CpuManufacturers = flex.ExpandStringSet(v) + } + + if v, ok := tfMap["excluded_instance_types"].(*schema.Set); ok && v.Len() > 0 { + apiObject.ExcludedInstanceTypes = flex.ExpandStringSet(v) + } + + if v, ok := tfMap["instance_generations"].(*schema.Set); ok && v.Len() > 0 { + apiObject.InstanceGenerations = flex.ExpandStringSet(v) + } + + if v, ok := tfMap["local_storage"].(string); ok && v != "" { + apiObject.LocalStorage = aws.String(v) + } + + if v, ok := tfMap["local_storage_types"].(*schema.Set); ok && v.Len() > 0 { + apiObject.LocalStorageTypes = flex.ExpandStringSet(v) + } + + if v, ok := tfMap["memory_gib_per_vcpu"].([]interface{}); ok && len(v) > 0 { + apiObject.MemoryGiBPerVCpu = expandMemoryGiBPerVCpuRequest(v[0].(map[string]interface{})) + } + + if v, ok := tfMap["memory_mib"].([]interface{}); ok && len(v) > 0 { + apiObject.MemoryMiB = expandMemoryMiBRequest(v[0].(map[string]interface{})) + } + + if v, ok := tfMap["network_interface_count"].([]interface{}); ok && len(v) > 0 { + apiObject.NetworkInterfaceCount = expandNetworkInterfaceCountRequest(v[0].(map[string]interface{})) + } + + if v, ok := tfMap["on_demand_max_price_percentage_over_lowest_price"].(int); ok && v != 0 { + apiObject.OnDemandMaxPricePercentageOverLowestPrice = aws.Int64(int64(v)) + } + + if v, ok := tfMap["require_hibernate_support"].(bool); ok && v { + apiObject.RequireHibernateSupport = aws.Bool(v) + } + + if v, ok := tfMap["spot_max_price_percentage_over_lowest_price"].(int); ok && v != 0 { + apiObject.SpotMaxPricePercentageOverLowestPrice = aws.Int64(int64(v)) + } + + if v, ok := tfMap["total_local_storage_gb"].([]interface{}); ok && len(v) > 0 { + apiObject.TotalLocalStorageGB = expandTotalLocalStorageGBRequest(v[0].(map[string]interface{})) + } + + if v, ok := tfMap["vcpu_count"].([]interface{}); ok && len(v) > 0 { + apiObject.VCpuCount = expandVCpuCountRangeRequest(v[0].(map[string]interface{})) + } + + return apiObject +} + +func expandAcceleratorCountRequest(tfMap map[string]interface{}) *ec2.AcceleratorCountRequest { + if tfMap == nil { + return nil + } + + apiObject := &ec2.AcceleratorCountRequest{} + + if v, ok := tfMap["max"].(int); ok { + apiObject.Max = aws.Int64(int64(v)) + } + + if v, ok := tfMap["min"].(int); ok { + apiObject.Min = aws.Int64(int64(v)) + } + + return apiObject +} + +func expandAcceleratorTotalMemoryMiBRequest(tfMap map[string]interface{}) *ec2.AcceleratorTotalMemoryMiBRequest { + if tfMap == nil { + return nil + } + + apiObject := &ec2.AcceleratorTotalMemoryMiBRequest{} + + if v, ok := tfMap["max"].(int); ok { + apiObject.Max = aws.Int64(int64(v)) + } + + if v, ok := tfMap["min"].(int); ok { + apiObject.Min = aws.Int64(int64(v)) + } + + return apiObject +} + +func expandBaselineEbsBandwidthMbpsRequest(tfMap map[string]interface{}) *ec2.BaselineEbsBandwidthMbpsRequest { + if tfMap == nil { + return nil + } + + apiObject := &ec2.BaselineEbsBandwidthMbpsRequest{} + + if v, ok := tfMap["max"].(int); ok { + apiObject.Max = aws.Int64(int64(v)) + } + + if v, ok := tfMap["min"].(int); ok { + apiObject.Min = aws.Int64(int64(v)) + } + + return apiObject +} + +func expandMemoryGiBPerVCpuRequest(tfMap map[string]interface{}) *ec2.MemoryGiBPerVCpuRequest { + if tfMap == nil { + return nil + } + + apiObject := &ec2.MemoryGiBPerVCpuRequest{} + + if v, ok := tfMap["max"].(float64); ok { + apiObject.Max = aws.Float64(v) + } + + if v, ok := tfMap["min"].(float64); ok { + apiObject.Min = aws.Float64(v) + } + + return apiObject +} + +func expandMemoryMiBRequest(tfMap map[string]interface{}) *ec2.MemoryMiBRequest { + if tfMap == nil { + return nil + } + + apiObject := &ec2.MemoryMiBRequest{} + + if v, ok := tfMap["max"].(int); ok { + apiObject.Max = aws.Int64(int64(v)) + } + + if v, ok := tfMap["min"].(int); ok { + apiObject.Min = aws.Int64(int64(v)) + } + + return apiObject +} + +func expandNetworkInterfaceCountRequest(tfMap map[string]interface{}) *ec2.NetworkInterfaceCountRequest { + if tfMap == nil { + return nil + } + + apiObject := &ec2.NetworkInterfaceCountRequest{} + + if v, ok := tfMap["max"].(int); ok { + apiObject.Max = aws.Int64(int64(v)) + } + + if v, ok := tfMap["min"].(int); ok { + apiObject.Min = aws.Int64(int64(v)) + } + + return apiObject +} + +func expandTotalLocalStorageGBRequest(tfMap map[string]interface{}) *ec2.TotalLocalStorageGBRequest { + if tfMap == nil { + return nil + } + + apiObject := &ec2.TotalLocalStorageGBRequest{} + + if v, ok := tfMap["max"].(float64); ok { + apiObject.Max = aws.Float64(v) + } + + if v, ok := tfMap["min"].(float64); ok { + apiObject.Min = aws.Float64(v) + } + + return apiObject +} + +func expandVCpuCountRangeRequest(tfMap map[string]interface{}) *ec2.VCpuCountRangeRequest { + if tfMap == nil { + return nil + } + + apiObject := &ec2.VCpuCountRangeRequest{} + + if v, ok := tfMap["max"].(int); ok { + apiObject.Max = aws.Int64(int64(v)) + } + + if v, ok := tfMap["min"].(int); ok { + apiObject.Min = aws.Int64(int64(v)) + } + + return apiObject +} + func expandLaunchTemplateSpotMarketOptionsRequest(tfMap map[string]interface{}) *ec2.LaunchTemplateSpotMarketOptionsRequest { if tfMap == nil { return nil @@ -1710,6 +2199,13 @@ func flattenResponseLaunchTemplateData(d *schema.ResourceData, apiObject *ec2.Re } else { d.Set("instance_market_options", nil) } + if apiObject.InstanceRequirements != nil { + if err := d.Set("instance_requirements", []interface{}{flattenInstanceRequirements(apiObject.InstanceRequirements)}); err != nil { + return fmt.Errorf("error setting instance_requirements: %w", err) + } + } else { + d.Set("instance_requirements", nil) + } d.Set("instance_type", apiObject.InstanceType) d.Set("kernel_id", apiObject.KernelId) d.Set("key_name", apiObject.KeyName) @@ -2005,6 +2501,244 @@ func flattenLaunchTemplateInstanceMarketOptions(apiObject *ec2.LaunchTemplateIns return tfMap } +func flattenInstanceRequirements(apiObject *ec2.InstanceRequirements) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.AcceleratorCount; v != nil { + tfMap["accelerator_count"] = []interface{}{flattenAcceleratorCount(v)} + } + + if v := apiObject.AcceleratorManufacturers; v != nil { + tfMap["accelerator_manufacturers"] = aws.StringValueSlice(v) + } + + if v := apiObject.AcceleratorNames; v != nil { + tfMap["accelerator_names"] = aws.StringValueSlice(v) + } + + if v := apiObject.AcceleratorTotalMemoryMiB; v != nil { + tfMap["accelerator_total_memory_mib"] = []interface{}{flattenAcceleratorTotalMemoryMiB(v)} + } + + if v := apiObject.AcceleratorTypes; v != nil { + tfMap["accelerator_types"] = aws.StringValueSlice(v) + } + + if v := apiObject.BareMetal; v != nil { + tfMap["bare_metal"] = aws.StringValue(v) + } + + if v := apiObject.BaselineEbsBandwidthMbps; v != nil { + tfMap["baseline_ebs_bandwidth_mbps"] = []interface{}{flattenBaselineEbsBandwidthMbps(v)} + } + + if v := apiObject.BurstablePerformance; v != nil { + tfMap["burstable_performance"] = aws.StringValue(v) + } + + if v := apiObject.CpuManufacturers; v != nil { + tfMap["cpu_manufacturers"] = aws.StringValueSlice(v) + } + + if v := apiObject.ExcludedInstanceTypes; v != nil { + tfMap["excluded_instance_types"] = aws.StringValueSlice(v) + } + + if v := apiObject.InstanceGenerations; v != nil { + tfMap["instance_generations"] = aws.StringValueSlice(v) + } + + if v := apiObject.LocalStorage; v != nil { + tfMap["local_storage"] = aws.StringValue(v) + } + + if v := apiObject.LocalStorageTypes; v != nil { + tfMap["local_storage_types"] = aws.StringValueSlice(v) + } + + if v := apiObject.MemoryGiBPerVCpu; v != nil { + tfMap["memory_gib_per_vcpu"] = []interface{}{flattenMemoryGiBPerVCpu(v)} + } + + if v := apiObject.MemoryMiB; v != nil { + tfMap["memory_mib"] = []interface{}{flattenMemoryMiB(v)} + } + + if v := apiObject.NetworkInterfaceCount; v != nil { + tfMap["network_interface_count"] = []interface{}{flattenNetworkInterfaceCount(v)} + } + + if v := apiObject.OnDemandMaxPricePercentageOverLowestPrice; v != nil { + tfMap["on_demand_max_price_percentage_over_lowest_price"] = aws.Int64Value(v) + } + + if v := apiObject.RequireHibernateSupport; v != nil { + tfMap["require_hibernate_support"] = aws.BoolValue(v) + } + + if v := apiObject.SpotMaxPricePercentageOverLowestPrice; v != nil { + tfMap["spot_max_price_percentage_over_lowest_price"] = aws.Int64Value(v) + } + + if v := apiObject.TotalLocalStorageGB; v != nil { + tfMap["total_local_storage_gb"] = []interface{}{flattenTotalLocalStorageGB(v)} + } + + if v := apiObject.VCpuCount; v != nil { + tfMap["vcpu_count"] = []interface{}{flattenVCpuCountRange(v)} + } + + return tfMap +} + +func flattenAcceleratorCount(apiObject *ec2.AcceleratorCount) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.Max; v != nil { + tfMap["max"] = aws.Int64Value(v) + } + + if v := apiObject.Min; v != nil { + tfMap["min"] = aws.Int64Value(v) + } + + return tfMap +} + +func flattenAcceleratorTotalMemoryMiB(apiObject *ec2.AcceleratorTotalMemoryMiB) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.Max; v != nil { + tfMap["max"] = aws.Int64Value(v) + } + + if v := apiObject.Min; v != nil { + tfMap["min"] = aws.Int64Value(v) + } + + return tfMap +} + +func flattenBaselineEbsBandwidthMbps(apiObject *ec2.BaselineEbsBandwidthMbps) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.Max; v != nil { + tfMap["max"] = aws.Int64Value(v) + } + + if v := apiObject.Min; v != nil { + tfMap["min"] = aws.Int64Value(v) + } + + return tfMap +} + +func flattenMemoryGiBPerVCpu(apiObject *ec2.MemoryGiBPerVCpu) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.Max; v != nil { + tfMap["max"] = aws.Float64Value(v) + } + + if v := apiObject.Min; v != nil { + tfMap["min"] = aws.Float64Value(v) + } + + return tfMap +} + +func flattenMemoryMiB(apiObject *ec2.MemoryMiB) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.Max; v != nil { + tfMap["max"] = aws.Int64Value(v) + } + + if v := apiObject.Min; v != nil { + tfMap["min"] = aws.Int64Value(v) + } + + return tfMap +} + +func flattenNetworkInterfaceCount(apiObject *ec2.NetworkInterfaceCount) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.Max; v != nil { + tfMap["max"] = aws.Int64Value(v) + } + + if v := apiObject.Min; v != nil { + tfMap["min"] = aws.Int64Value(v) + } + + return tfMap +} + +func flattenTotalLocalStorageGB(apiObject *ec2.TotalLocalStorageGB) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.Max; v != nil { + tfMap["max"] = aws.Float64Value(v) + } + + if v := apiObject.Min; v != nil { + tfMap["min"] = aws.Float64Value(v) + } + + return tfMap +} + +func flattenVCpuCountRange(apiObject *ec2.VCpuCountRange) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.Max; v != nil { + tfMap["max"] = aws.Int64Value(v) + } + + if v := apiObject.Min; v != nil { + tfMap["min"] = aws.Int64Value(v) + } + + return tfMap +} + func flattenLaunchTemplateSpotMarketOptions(apiObject *ec2.LaunchTemplateSpotMarketOptions) map[string]interface{} { if apiObject == nil { return nil diff --git a/internal/service/ec2/ec2_launch_template_data_source.go b/internal/service/ec2/ec2_launch_template_data_source.go index 33694c1f2223..a2bbb233af21 100644 --- a/internal/service/ec2/ec2_launch_template_data_source.go +++ b/internal/service/ec2/ec2_launch_template_data_source.go @@ -272,6 +272,201 @@ func DataSourceLaunchTemplate() *schema.Resource { }, }, }, + "instance_requirements": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "accelerator_count": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeInt, + Computed: true, + }, + "min": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "accelerator_manufacturers": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "accelerator_names": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "accelerator_total_memory_mib": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeInt, + Computed: true, + }, + "min": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "accelerator_types": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "bare_metal": { + Type: schema.TypeString, + Computed: true, + }, + "baseline_ebs_bandwidth_mbps": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeInt, + Computed: true, + }, + "min": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "burstable_performance": { + Type: schema.TypeString, + Computed: true, + }, + "cpu_manufacturers": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "excluded_instance_types": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "instance_generations": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "local_storage": { + Type: schema.TypeString, + Computed: true, + }, + "local_storage_types": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "memory_gib_per_vcpu": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeFloat, + Computed: true, + }, + "min": { + Type: schema.TypeFloat, + Computed: true, + }, + }, + }, + }, + "memory_mib": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeInt, + Computed: true, + }, + "min": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "network_interface_count": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeInt, + Computed: true, + }, + "min": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "on_demand_max_price_percentage_over_lowest_price": { + Type: schema.TypeInt, + Computed: true, + }, + "require_hibernate_support": { + Type: schema.TypeBool, + Computed: true, + }, + "spot_max_price_percentage_over_lowest_price": { + Type: schema.TypeInt, + Computed: true, + }, + "total_local_storage_gb": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeFloat, + Computed: true, + }, + "min": { + Type: schema.TypeFloat, + Computed: true, + }, + }, + }, + }, + "vcpu_count": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max": { + Type: schema.TypeInt, + Computed: true, + }, + "min": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + }, + }, + }, "instance_type": { Type: schema.TypeString, Computed: true, diff --git a/internal/service/ec2/ec2_launch_template_data_source_test.go b/internal/service/ec2/ec2_launch_template_data_source_test.go index d8e84b059fcf..69a3c046a26e 100644 --- a/internal/service/ec2/ec2_launch_template_data_source_test.go +++ b/internal/service/ec2/ec2_launch_template_data_source_test.go @@ -41,6 +41,7 @@ func TestAccEC2LaunchTemplateDataSource_name(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "image_id", dataSourceName, "image_id"), resource.TestCheckResourceAttrPair(resourceName, "instance_initiated_shutdown_behavior", dataSourceName, "instance_initiated_shutdown_behavior"), resource.TestCheckResourceAttrPair(resourceName, "instance_market_options.#", dataSourceName, "instance_market_options.#"), + resource.TestCheckResourceAttrPair(resourceName, "instance_requirements.#", dataSourceName, "instance_requirements.#"), resource.TestCheckResourceAttrPair(resourceName, "instance_type", dataSourceName, "instance_type"), resource.TestCheckResourceAttrPair(resourceName, "kernel_id", dataSourceName, "kernel_id"), resource.TestCheckResourceAttrPair(resourceName, "key_name", dataSourceName, "key_name"), diff --git a/internal/service/ec2/ec2_launch_template_test.go b/internal/service/ec2/ec2_launch_template_test.go index 18d2c7d12494..fb6d4d54656a 100644 --- a/internal/service/ec2/ec2_launch_template_test.go +++ b/internal/service/ec2/ec2_launch_template_test.go @@ -48,6 +48,7 @@ func TestAccEC2LaunchTemplate_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "image_id", ""), resource.TestCheckResourceAttr(resourceName, "instance_initiated_shutdown_behavior", ""), resource.TestCheckResourceAttr(resourceName, "instance_market_options.#", "0"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "0"), resource.TestCheckResourceAttr(resourceName, "instance_type", ""), resource.TestCheckResourceAttr(resourceName, "kernel_id", ""), resource.TestCheckResourceAttr(resourceName, "key_name", ""), @@ -1294,6 +1295,1331 @@ func TestAccEC2LaunchTemplate_instanceMarketOptions(t *testing.T) { }) } +func TestAccEC2LaunchTemplate_instanceRequirements_memoryMiBAndVCpuCount(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.memory_mib.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.memory_mib.0.min", "500"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.vcpu_count.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.vcpu_count.0.min", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `memory_mib { + min = 500 + max = 4000 + } + vcpu_count { + min = 1 + max = 8 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.memory_mib.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.memory_mib.0.min", "500"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.memory_mib.0.max", "4000"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.vcpu_count.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.vcpu_count.0.min", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.vcpu_count.0.max", "8"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_acceleratorCount(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `accelerator_count { + min = 1 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_count.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_count.0.min", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `accelerator_count { + min = 1 + max = 4 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_count.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_count.0.min", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_count.0.max", "4"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `accelerator_count { + max = 0 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_count.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_count.0.max", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_acceleratorManufacturers(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `accelerator_manufacturers = ["amd"] + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_manufacturers.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_manufacturers.*", "amd"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `accelerator_manufacturers = ["amazon-web-services", "amd", "nvidia", "xilinx"] + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_manufacturers.#", "4"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_manufacturers.*", "amazon-web-services"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_manufacturers.*", "amd"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_manufacturers.*", "nvidia"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_manufacturers.*", "xilinx"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_acceleratorNames(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `accelerator_names = ["a100"] + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_names.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_names.*", "a100"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `accelerator_names = ["a100", "v100", "k80", "t4", "m60", "radeon-pro-v520", "vu9p"] + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_names.#", "7"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_names.*", "a100"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_names.*", "v100"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_names.*", "k80"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_names.*", "t4"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_names.*", "m60"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_names.*", "radeon-pro-v520"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_names.*", "vu9p"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_acceleratorTotalMemoryMiB(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `accelerator_total_memory_mib { + min = 1000 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_total_memory_mib.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_total_memory_mib.0.min", "1000"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `accelerator_total_memory_mib { + max = 24000 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_total_memory_mib.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_total_memory_mib.0.max", "24000"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `accelerator_total_memory_mib { + min = 1000 + max = 24000 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_total_memory_mib.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_total_memory_mib.0.min", "1000"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_total_memory_mib.0.max", "24000"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_acceleratorTypes(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `accelerator_types = ["fpga"] + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_types.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_types.*", "fpga"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `accelerator_types = ["fpga", "gpu", "inference"] + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.accelerator_types.#", "3"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_types.*", "fpga"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_types.*", "gpu"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.accelerator_types.*", "inference"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_bareMetal(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `bare_metal = "excluded" + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.bare_metal", "excluded"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `bare_metal = "included" + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.bare_metal", "included"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `bare_metal = "required" + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.bare_metal", "required"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_baselineEbsBandwidthMbps(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `baseline_ebs_bandwidth_mbps { + min = 10 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.baseline_ebs_bandwidth_mbps.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.baseline_ebs_bandwidth_mbps.0.min", "10"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `baseline_ebs_bandwidth_mbps { + max = 20000 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.baseline_ebs_bandwidth_mbps.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.baseline_ebs_bandwidth_mbps.0.max", "20000"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `baseline_ebs_bandwidth_mbps { + min = 10 + max = 20000 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.baseline_ebs_bandwidth_mbps.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.baseline_ebs_bandwidth_mbps.0.min", "10"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.baseline_ebs_bandwidth_mbps.0.max", "20000"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_burstablePerformance(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `burstable_performance = "excluded" + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.burstable_performance", "excluded"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `burstable_performance = "included" + memory_mib { + min = 1000 + } + vcpu_count { + min = 2 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.burstable_performance", "included"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `burstable_performance = "required" + memory_mib { + min = 1000 + } + vcpu_count { + min = 2 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.burstable_performance", "required"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_cpuManufacturers(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `cpu_manufacturers = ["amd"] + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.cpu_manufacturers.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.cpu_manufacturers.*", "amd"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `cpu_manufacturers = ["amazon-web-services", "amd", "intel"] + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.cpu_manufacturers.#", "3"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.cpu_manufacturers.*", "amazon-web-services"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.cpu_manufacturers.*", "amd"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.cpu_manufacturers.*", "intel"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_excludedInstanceTypes(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `excluded_instance_types = ["t2.nano"] + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.excluded_instance_types.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.excluded_instance_types.*", "t2.nano"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `excluded_instance_types = ["t2.nano", "t3*", "t4g.*"] + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.excluded_instance_types.#", "3"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.excluded_instance_types.*", "t2.nano"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.excluded_instance_types.*", "t3*"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.excluded_instance_types.*", "t4g.*"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_instanceGenerations(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `instance_generations = ["current"] + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.instance_generations.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.instance_generations.*", "current"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `instance_generations = ["current", "previous"] + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.instance_generations.#", "2"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.instance_generations.*", "current"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.instance_generations.*", "previous"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_localStorage(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `local_storage = "excluded" + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.local_storage", "excluded"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `local_storage = "included" + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.local_storage", "included"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `local_storage = "required" + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.local_storage", "required"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_localStorageTypes(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `local_storage_types = ["hdd"] + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.local_storage_types.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.local_storage_types.*", "hdd"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `local_storage_types = ["hdd", "ssd"] + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.local_storage_types.#", "2"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.local_storage_types.*", "hdd"), + resource.TestCheckTypeSetElemAttr(resourceName, "instance_requirements.0.local_storage_types.*", "ssd"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_memoryGiBPerVCpu(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `memory_gib_per_vcpu { + min = 0.5 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.memory_gib_per_vcpu.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.memory_gib_per_vcpu.0.min", "0.5"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `memory_gib_per_vcpu { + max = 9.5 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.memory_gib_per_vcpu.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.memory_gib_per_vcpu.0.max", "9.5"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `memory_gib_per_vcpu { + min = 0.5 + max = 9.5 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.memory_gib_per_vcpu.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.memory_gib_per_vcpu.0.min", "0.5"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.memory_gib_per_vcpu.0.max", "9.5"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_networkInterfaceCount(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `network_interface_count { + min = 1 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.network_interface_count.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.network_interface_count.0.min", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `network_interface_count { + max = 10 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.network_interface_count.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.network_interface_count.0.max", "10"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `network_interface_count { + min = 1 + max = 10 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.network_interface_count.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.network_interface_count.0.min", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.network_interface_count.0.max", "10"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_onDemandMaxPricePercentageOverLowestPrice(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `on_demand_max_price_percentage_over_lowest_price = 50 + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.on_demand_max_price_percentage_over_lowest_price", "50"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_requireHibernateSupport(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `require_hibernate_support = false + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.require_hibernate_support", "false"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `require_hibernate_support = true + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.require_hibernate_support", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_spotMaxPricePercentageOverLowestPrice(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `spot_max_price_percentage_over_lowest_price = 75 + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.spot_max_price_percentage_over_lowest_price", "75"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccEC2LaunchTemplate_instanceRequirements_totalLocalStorageGB(t *testing.T) { + var template ec2.LaunchTemplate + resourceName := "aws_launch_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccCheckLaunchTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `total_local_storage_gb { + min = 0.5 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.total_local_storage_gb.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.total_local_storage_gb.0.min", "0.5"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `total_local_storage_gb { + max = 20.5 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.total_local_storage_gb.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.total_local_storage_gb.0.max", "20.5"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccLaunchTemplateConfig_instanceRequirements(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), + `total_local_storage_gb { + min = 0.5 + max = 20.5 + } + memory_mib { + min = 500 + } + vcpu_count { + min = 1 + }`), + Check: resource.ComposeTestCheckFunc( + testAccCheckLaunchTemplateExists(resourceName, &template), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.total_local_storage_gb.#", "1"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.total_local_storage_gb.0.min", "0.5"), + resource.TestCheckResourceAttr(resourceName, "instance_requirements.0.total_local_storage_gb.0.max", "20.5"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccEC2LaunchTemplate_licenseSpecification(t *testing.T) { var template ec2.LaunchTemplate resourceName := "aws_launch_template.test" @@ -2449,6 +3775,29 @@ resource "aws_autoscaling_group" "test" { `, rName)) } +func testAccLaunchTemplateConfig_instanceRequirements(rName, instanceRequirements 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" { + name = %[1]q + image_id = data.aws_ami.test.id + + instance_requirements { + %[2]s + } +} +`, rName, instanceRequirements) +} + func testAccLaunchTemplateConfig_metadataOptions(rName string) string { return fmt.Sprintf(` resource "aws_launch_template" "test" { diff --git a/internal/verify/validate.go b/internal/verify/validate.go index 4c7ebd098a92..5adfe2f2f498 100644 --- a/internal/verify/validate.go +++ b/internal/verify/validate.go @@ -349,3 +349,22 @@ var ValidStringDateOrPositiveInt = validation.Any( validation.IsRFC3339Time, validation.StringMatch(regexp.MustCompile(`^\d+$`), "must be a positive integer value"), ) + +// FloatGreaterThan returns a SchemaValidateFunc which tests if the provided value +// is of type float and is greater than threshold. +func FloatGreaterThan(threshold float64) schema.SchemaValidateFunc { + return func(i interface{}, k string) (s []string, es []error) { + v, ok := i.(float64) + if !ok { + es = append(es, fmt.Errorf("expected type of %s to be float", k)) + return + } + + if v <= threshold { + es = append(es, fmt.Errorf("expected %s to be greater than (%f), got %f", k, threshold, v)) + return + } + + return + } +} diff --git a/internal/verify/validate_test.go b/internal/verify/validate_test.go index 321c827839a7..8f1db93a4e9a 100644 --- a/internal/verify/validate_test.go +++ b/internal/verify/validate_test.go @@ -5,6 +5,7 @@ import ( "strings" "testing" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) @@ -645,3 +646,35 @@ func TestValidateTypeStringIsDateOrInt(t *testing.T) { } } } + +func TestFloatGreaterThan(t *testing.T) { + cases := map[string]struct { + Value interface{} + ValidateFunc schema.SchemaValidateFunc + ExpectValidationErrors bool + }{ + "accept valid value": { + Value: 1.5, + ValidateFunc: FloatGreaterThan(1.0), + }, + "reject invalid value gt": { + Value: 1.5, + ValidateFunc: FloatGreaterThan(2.0), + ExpectValidationErrors: true, + }, + "reject invalid value eq": { + Value: 1.5, + ValidateFunc: FloatGreaterThan(1.5), + ExpectValidationErrors: true, + }, + } + + for tn, tc := range cases { + _, errors := tc.ValidateFunc(tc.Value, tn) + if len(errors) > 0 && !tc.ExpectValidationErrors { + t.Errorf("%s: unexpected errors %s", tn, errors) + } else if len(errors) == 0 && tc.ExpectValidationErrors { + t.Errorf("%s: expected errors but got none", tn) + } + } +} diff --git a/website/docs/r/launch_template.html.markdown b/website/docs/r/launch_template.html.markdown index 5ffccee6613a..361f9950f58e 100644 --- a/website/docs/r/launch_template.html.markdown +++ b/website/docs/r/launch_template.html.markdown @@ -133,7 +133,8 @@ The following arguments are supported: (Default: `stop`). * `instance_market_options` - (Optional) The market (purchasing) option for the instance. See [Market Options](#market-options) below for details. -* `instance_type` - (Optional) The type of the instance. +* `instance_requirements` - (Optional) The attribute requirements for the type of instance. If present then `instance_type` cannot be present. +* `instance_type` - (Optional) The type of the instance. If present then `instance_requirements` cannot be present. * `kernel_id` - (Optional) The kernel ID. * `key_name` - (Optional) The key name to use for the instance. * `license_specification` - (Optional) A list of license specifications to associate with. See [License Specification](#license-specification) below for more details. @@ -257,6 +258,107 @@ The `iam_instance_profile` block supports the following: * `arn` - The Amazon Resource Name (ARN) of the instance profile. * `name` - The name of the instance profile. +### Instance Requirements + +This configuration block supports the following: + +~> **NOTE**: Both `memory_mib.min` and `vcpu_count.min` must be specified. + +* `accelerator_count` - (Optional) Block describing the minimum and maximum number of accelerators (GPUs, FPGAs, or AWS Inferentia chips). Default is no minimum or maximum. + * `min` - (Optional) Minimum. + * `max` - (Optional) Maximum. Set to `0` to exclude instance types with accelerators. +* `accelerator_manufacturers` - (Optional) List of accelerator manufacturer names. Default is any manufacturer. + + ``` + Valid names: + * amazon-web-services + * amd + * nvidia + * xilinx + ``` + +* `accelerator_names` - (Optional) List of accelerator names. Default is any acclerator. + + ``` + Valid names: + * a100 - NVIDIA A100 GPUs + * v100 - NVIDIA V100 GPUs + * k80 - NVIDIA K80 GPUs + * t4 - NVIDIA T4 GPUs + * m60 - NVIDIA M60 GPUs + * radeon-pro-v520 - AMD Radeon Pro V520 GPUs + * vu9p - Xilinx VU9P FPGAs + ``` + +* `accelerator_total_memory_mib` - (Optional) Block describing the minimum and maximum total memory of the accelerators. Default is no minimum or maximum. + * `min` - (Optional) Minimum. + * `max` - (Optional) Maximum. +* `accelerator_types` - (Optional) List of accelerator types. Default is any accelerator type. + + ``` + Valid types: + * fpga + * gpu + * inference + ``` + +* `bare_metal` - (Optional) Indicate whether bare metal instace types should be `included`, `excluded`, or `required`. Default is `excluded`. +* `baseline_ebs_bandwidth_mbps` - (Optional) Block describing the minimum and maximum baseline EBS bandwidth, in Mbps. Default is no minimum or maximum. + * `min` - (Optional) Minimum. + * `max` - (Optional) Maximum. +* `burstable_performance` - (Optional) Indicate whether burstable performance instance types should be `included`, `excluded`, or `required`. Default is `excluded`. +* `cpu_manufacturers` (Optional) List of CPU manufacturer names. Default is any manufacturer. + + ~> **NOTE**: Don't confuse the CPU hardware manufacturer with the CPU hardware architecture. Instances will be launched with a compatible CPU architecture based on the Amazon Machine Image (AMI) that you specify in your launch template. + + ``` + Valid names: + * amazon-web-services + * amd + * intel + ``` + +* `excluded_instance_types` - (Optional) List of instance types to exclude. You can use strings with one or more wild cards, represented by an asterisk (\*). The following are examples: `c5*`, `m5a.*`, `r*`, `*3*`. For example, if you specify `c5*`, you are excluding the entire C5 instance family, which includes all C5a and C5n instance types. If you specify `m5a.*`, you are excluding all the M5a instance types, but not the M5n instance types. Maximum of 400 entries in the list; each entry is limited to 30 characters. Default is no excluded instance types. +* `instance_generations` - (Optional) List of instance generation names. Default is any generation. + + ``` + Valid names: + * current - Recommended for best performance. + * previous - For existing applications optimized for older instance types. + ``` + +* `local_storage` - (Optional) Indicate whether instance types with local storage volumes are `included`, `excluded`, or `required`. Default is `included`. +* `local_storage_types` - (Optional) List of local storage type names. Default any storage type. + + ``` + Value names: + * hdd - hard disk drive + * ssd - solid state drive + ``` + +* `memory_gib_per_vcpu` - (Optional) Block describing the minimum and maximum amount of memory (GiB) per vCPU. Default is no minimum or maximum. + * `min` - (Optional) Minimum. May be a decimal number, e.g. `0.5`. + * `max` - (Optional) Maximum. May be a decimal number, e.g. `0.5`. +* `memory_mib` - (Required) Block describing the minimum and maximum amount of memory (MiB). Default is no maximum. + * `min` - (Required) Minimum. + * `max` - (Optional) Maximum. +* `network_interface_count` - (Optional) Block describing the minimum and maximum number of network interfaces. Default is no minimum or maximum. + * `min` - (Optional) Minimum. + * `max` - (Optional) Maximum. +* `on_demand_max_price_percentage_over_lowest_price` - (Optional) The price protection threshold for On-Demand Instances. This is the maximum you’ll pay for an On-Demand Instance, expressed as a percentage higher than the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 Auto Scaling selects instance types with your attributes, we will exclude instance types whose price is higher than your threshold. The parameter accepts an integer, which Amazon EC2 Auto Scaling interprets as a percentage. To turn off price protection, specify a high value, such as 999999. Default is 20. + + If you set DesiredCapacityType to vcpu or memory-mib, the price protection threshold is applied based on the per vCPU or per memory price instead of the per instance price. +* `require_hibernate_support` - (Optional) Indicate whether instance types must support On-Demand Instance Hibernation, either `true` or `false`. Default is `false`. +* `spot_max_price_percentage_over_lowest_price` - (Optional) The price protection threshold for Spot Instances. This is the maximum you’ll pay for a Spot Instance, expressed as a percentage higher than the cheapest M, C, or R instance type with your specified attributes. When Amazon EC2 Auto Scaling selects instance types with your attributes, we will exclude instance types whose price is higher than your threshold. The parameter accepts an integer, which Amazon EC2 Auto Scaling interprets as a percentage. To turn off price protection, specify a high value, such as 999999. Default is 100. + + If you set DesiredCapacityType to vcpu or memory-mib, the price protection threshold is applied based on the per vCPU or per memory price instead of the per instance price. +* `total_local_storage_gb` - (Optional) Block describing the minimum and maximum total local storage (GB). Default is no minimum or maximum. + * `min` - (Optional) Minimum. May be a decimal number, e.g. `0.5`. + * `max` - (Optional) Maximum. May be a decimal number, e.g. `0.5`. +* `vcpu_count` - (Required) Block describing the minimum and maximum number of vCPUs. Default is no maximum. + * `min` - (Required) Minimum. + * `max` - (Optional) Maximum. + ### License Specification Associate one of more license configurations.