@@ -1987,62 +1987,6 @@ func blockDeviceIsRoot(bd *ec2.InstanceBlockDeviceMapping, instance *ec2.Instanc
1987
1987
aws .StringValue (bd .DeviceName ) == aws .StringValue (instance .RootDeviceName )
1988
1988
}
1989
1989
1990
- func fetchLaunchTemplateAMI (specs []interface {}, conn * ec2.EC2 ) (string , error ) {
1991
- if len (specs ) < 1 {
1992
- return "" , errors .New ("Cannot fetch AMI for blank launch template." )
1993
- }
1994
-
1995
- spec := specs [0 ].(map [string ]interface {})
1996
-
1997
- idValue , idOk := spec ["id" ]
1998
- nameValue , nameOk := spec ["name" ]
1999
-
2000
- request := & ec2.DescribeLaunchTemplateVersionsInput {}
2001
-
2002
- if idOk && idValue != "" {
2003
- request .LaunchTemplateId = aws .String (idValue .(string ))
2004
- } else if nameOk && nameValue != "" {
2005
- request .LaunchTemplateName = aws .String (nameValue .(string ))
2006
- }
2007
-
2008
- var isLatest bool
2009
- defaultFilter := []* ec2.Filter {
2010
- {
2011
- Name : aws .String ("is-default-version" ),
2012
- Values : aws .StringSlice ([]string {"true" }),
2013
- },
2014
- }
2015
- if v , ok := spec ["version" ]; ok && v != "" {
2016
- switch v {
2017
- case LaunchTemplateVersionDefault :
2018
- request .Filters = defaultFilter
2019
- case LaunchTemplateVersionLatest :
2020
- isLatest = true
2021
- default :
2022
- request .Versions = []* string {aws .String (v .(string ))}
2023
- }
2024
- }
2025
-
2026
- dltv , err := conn .DescribeLaunchTemplateVersions (request )
2027
- if err != nil {
2028
- return "" , err
2029
- }
2030
-
2031
- var ltData * ec2.ResponseLaunchTemplateData
2032
- if isLatest {
2033
- index := len (dltv .LaunchTemplateVersions ) - 1
2034
- ltData = dltv .LaunchTemplateVersions [index ].LaunchTemplateData
2035
- } else {
2036
- ltData = dltv .LaunchTemplateVersions [0 ].LaunchTemplateData
2037
- }
2038
-
2039
- if ltData .ImageId != nil {
2040
- return * ltData .ImageId , nil
2041
- }
2042
-
2043
- return "" , nil
2044
- }
2045
-
2046
1990
func FetchRootDeviceName (conn * ec2.EC2 , amiID string ) (* string , error ) {
2047
1991
if amiID == "" {
2048
1992
return nil , errors .New ("Cannot fetch root device name for blank AMI ID." )
@@ -2290,21 +2234,24 @@ func readBlockDeviceMappingsFromConfig(d *schema.ResourceData, conn *ec2.EC2) ([
2290
2234
}
2291
2235
2292
2236
var amiID string
2293
- if v , ok := d .GetOk ("launch_template" ); ok {
2294
- var err error
2295
- amiID , err = fetchLaunchTemplateAMI (v .([]interface {}), conn )
2237
+
2238
+ if v , ok := d .GetOk ("launch_template" ); ok && len (v .([]interface {})) > 0 && v .([]interface {})[0 ] != nil {
2239
+ launchTemplateData , err := findLaunchTemplateData (conn , expandLaunchTemplateSpecification (v .([]interface {})[0 ].(map [string ]interface {})))
2240
+
2296
2241
if err != nil {
2297
2242
return nil , err
2298
2243
}
2244
+
2245
+ amiID = aws .StringValue (launchTemplateData .ImageId )
2299
2246
}
2300
2247
2301
- // AMI id from attributes overrides ami from launch template
2248
+ // AMI from configuration overrides the one from the launch template.
2302
2249
if v , ok := d .GetOk ("ami" ); ok {
2303
2250
amiID = v .(string )
2304
2251
}
2305
2252
2306
2253
if amiID == "" {
2307
- return nil , errors .New ("`ami` must be set or provided via launch template " )
2254
+ return nil , errors .New ("`ami` must be set or provided via `launch_template` " )
2308
2255
}
2309
2256
2310
2257
if dn , err := FetchRootDeviceName (conn , amiID ); err == nil {
@@ -2506,8 +2453,21 @@ func buildInstanceOpts(d *schema.ResourceData, meta interface{}) (*awsInstanceOp
2506
2453
opts .InstanceType = aws .String (v .(string ))
2507
2454
}
2508
2455
2509
- if v , ok := d .GetOk ("launch_template" ); ok {
2510
- opts .LaunchTemplate = expandLaunchTemplateSpecification (v .([]interface {}))
2456
+ var instanceInterruptionBehavior string
2457
+
2458
+ if v , ok := d .GetOk ("launch_template" ); ok && len (v .([]interface {})) > 0 && v .([]interface {})[0 ] != nil {
2459
+ launchTemplateSpecification := expandLaunchTemplateSpecification (v .([]interface {})[0 ].(map [string ]interface {}))
2460
+ launchTemplateData , err := findLaunchTemplateData (conn , launchTemplateSpecification )
2461
+
2462
+ if err != nil {
2463
+ return nil , err
2464
+ }
2465
+
2466
+ opts .LaunchTemplate = launchTemplateSpecification
2467
+
2468
+ if launchTemplateData .InstanceMarketOptions != nil && launchTemplateData .InstanceMarketOptions .SpotOptions != nil {
2469
+ instanceInterruptionBehavior = aws .StringValue (launchTemplateData .InstanceMarketOptions .SpotOptions .InstanceInterruptionBehavior )
2470
+ }
2511
2471
}
2512
2472
2513
2473
instanceType := d .Get ("instance_type" ).(string )
@@ -2561,7 +2521,6 @@ func buildInstanceOpts(d *schema.ResourceData, meta interface{}) (*awsInstanceOp
2561
2521
// aws_spot_instance_request. They represent the same data. :-|
2562
2522
opts .Placement = & ec2.Placement {
2563
2523
AvailabilityZone : aws .String (d .Get ("availability_zone" ).(string )),
2564
- GroupName : aws .String (d .Get ("placement_group" ).(string )),
2565
2524
}
2566
2525
2567
2526
if v , ok := d .GetOk ("placement_partition_number" ); ok {
@@ -2570,7 +2529,11 @@ func buildInstanceOpts(d *schema.ResourceData, meta interface{}) (*awsInstanceOp
2570
2529
2571
2530
opts .SpotPlacement = & ec2.SpotPlacement {
2572
2531
AvailabilityZone : aws .String (d .Get ("availability_zone" ).(string )),
2573
- GroupName : aws .String (d .Get ("placement_group" ).(string )),
2532
+ }
2533
+
2534
+ if v := d .Get ("placement_group" ).(string ); instanceInterruptionBehavior == "" || instanceInterruptionBehavior == ec2 .InstanceInterruptionBehaviorTerminate {
2535
+ opts .Placement .GroupName = aws .String (v )
2536
+ opts .SpotPlacement .GroupName = aws .String (v )
2574
2537
}
2575
2538
2576
2539
if v := d .Get ("tenancy" ).(string ); v != "" {
@@ -3069,29 +3032,26 @@ func flattenInstanceMaintenanceOptions(apiObject *ec2.InstanceMaintenanceOptions
3069
3032
return tfMap
3070
3033
}
3071
3034
3072
- func expandLaunchTemplateSpecification (specs [ ]interface {}) * ec2.LaunchTemplateSpecification {
3073
- if len ( specs ) < 1 {
3035
+ func expandLaunchTemplateSpecification (tfMap map [ string ]interface {}) * ec2.LaunchTemplateSpecification {
3036
+ if tfMap == nil {
3074
3037
return nil
3075
3038
}
3076
3039
3077
- spec := specs [ 0 ].( map [ string ] interface {})
3040
+ apiObject := & ec2. LaunchTemplateSpecification {}
3078
3041
3079
- idValue , idOk := spec ["id" ]
3080
- nameValue , nameOk := spec ["name" ]
3081
-
3082
- result := & ec2.LaunchTemplateSpecification {}
3083
-
3084
- if idOk && idValue != "" {
3085
- result .LaunchTemplateId = aws .String (idValue .(string ))
3086
- } else if nameOk && nameValue != "" {
3087
- result .LaunchTemplateName = aws .String (nameValue .(string ))
3042
+ // DescribeLaunchTemplates returns both name and id but LaunchTemplateSpecification
3043
+ // allows only one of them to be set.
3044
+ if v , ok := tfMap ["id" ]; ok && v != "" {
3045
+ apiObject .LaunchTemplateId = aws .String (v .(string ))
3046
+ } else if v , ok := tfMap ["name" ]; ok && v != "" {
3047
+ apiObject .LaunchTemplateName = aws .String (v .(string ))
3088
3048
}
3089
3049
3090
- if v , ok := spec ["version" ]; ok && v != "" {
3091
- result .Version = aws .String (v .( string ) )
3050
+ if v , ok := tfMap ["version" ].( string ) ; ok && v != "" {
3051
+ apiObject .Version = aws .String (v )
3092
3052
}
3093
3053
3094
- return result
3054
+ return apiObject
3095
3055
}
3096
3056
3097
3057
func flattenInstanceLaunchTemplate (conn * ec2.EC2 , instanceID , previousLaunchTemplateVersion string ) ([]interface {}, error ) {
@@ -3176,6 +3136,43 @@ func findInstanceLaunchTemplateVersion(conn *ec2.EC2, id string) (string, error)
3176
3136
return launchTemplateVersion , nil
3177
3137
}
3178
3138
3139
+ func findLaunchTemplateData (conn * ec2.EC2 , launchTemplateSpecification * ec2.LaunchTemplateSpecification ) (* ec2.ResponseLaunchTemplateData , error ) {
3140
+ input := & ec2.DescribeLaunchTemplateVersionsInput {}
3141
+
3142
+ if v := aws .StringValue (launchTemplateSpecification .LaunchTemplateId ); v != "" {
3143
+ input .LaunchTemplateId = aws .String (v )
3144
+ } else if v := aws .StringValue (launchTemplateSpecification .LaunchTemplateName ); v != "" {
3145
+ input .LaunchTemplateName = aws .String (v )
3146
+ }
3147
+
3148
+ var latestVersion bool
3149
+
3150
+ if v := aws .StringValue (launchTemplateSpecification .Version ); v != "" {
3151
+ switch v {
3152
+ case LaunchTemplateVersionDefault :
3153
+ input .Filters = BuildAttributeFilterList (map [string ]string {
3154
+ "is-default-version" : "true" ,
3155
+ })
3156
+ case LaunchTemplateVersionLatest :
3157
+ latestVersion = true
3158
+ default :
3159
+ input .Versions = aws .StringSlice ([]string {v })
3160
+ }
3161
+ }
3162
+
3163
+ output , err := FindLaunchTemplateVersions (conn , input )
3164
+
3165
+ if err != nil {
3166
+ return nil , fmt .Errorf ("reading EC2 Launch Template versions: %w" , err )
3167
+ }
3168
+
3169
+ if latestVersion {
3170
+ return output [len (output )- 1 ].LaunchTemplateData , nil
3171
+ }
3172
+
3173
+ return output [0 ].LaunchTemplateData , nil
3174
+ }
3175
+
3179
3176
// findLaunchTemplateNameAndVersions returns the specified launch template's name, default version and latest version.
3180
3177
func findLaunchTemplateNameAndVersions (conn * ec2.EC2 , id string ) (string , string , string , error ) {
3181
3178
lt , err := FindLaunchTemplateByID (conn , id )
0 commit comments