@@ -54,46 +54,11 @@ func resourceCluster() *schema.Resource {
54
54
55
55
CustomizeDiff : customdiff .Sequence (
56
56
validateAutoModeCustomizeDiff ,
57
+ validateAutoModeComputeConfigCustomizeDiff ,
57
58
customdiff .ForceNewIfChange ("encryption_config" , func (_ context.Context , old , new , meta any ) bool {
58
59
// You cannot disable envelope encryption after enabling it. This action is irreversible.
59
60
return len (old .([]any )) == 1 && len (new .([]any )) == 0
60
61
}),
61
- func (ctx context.Context , rd * schema.ResourceDiff , meta any ) error {
62
- if rd .Id () == "" {
63
- return nil
64
- }
65
- oldValue , newValue := rd .GetChange ("compute_config" )
66
-
67
- oldComputeConfig := expandComputeConfigRequest (oldValue .([]any ))
68
- newComputeConfig := expandComputeConfigRequest (newValue .([]any ))
69
-
70
- if newComputeConfig == nil || oldComputeConfig == nil {
71
- return nil
72
- }
73
-
74
- oldRoleARN := aws .ToString (oldComputeConfig .NodeRoleArn )
75
- newRoleARN := aws .ToString (newComputeConfig .NodeRoleArn )
76
-
77
- newComputeConfigEnabled := aws .ToBool (newComputeConfig .Enabled )
78
-
79
- // Do not force new if auto mode is disabled in new config and role ARN is unset
80
- if ! newComputeConfigEnabled && newRoleARN == "" {
81
- return nil
82
- }
83
-
84
- // Do not force new if built-in node pools are zeroed in new config and role ARN is unset
85
- if len (newComputeConfig .NodePools ) == 0 && newRoleARN == "" {
86
- return nil
87
- }
88
-
89
- // only force new if an existing role has changed, not if a new role is added
90
- if oldRoleARN != "" && oldRoleARN != newRoleARN {
91
- if err := rd .ForceNew ("compute_config.0.node_role_arn" ); err != nil {
92
- return err
93
- }
94
- }
95
- return nil
96
- },
97
62
),
98
63
99
64
Timeouts : & schema.ResourceTimeout {
@@ -153,12 +118,14 @@ func resourceCluster() *schema.Resource {
153
118
"compute_config" : {
154
119
Type : schema .TypeList ,
155
120
Optional : true ,
121
+ Computed : true ,
156
122
MaxItems : 1 ,
157
123
Elem : & schema.Resource {
158
124
Schema : map [string ]* schema.Schema {
159
125
names .AttrEnabled : {
160
126
Type : schema .TypeBool ,
161
127
Optional : true ,
128
+ Default : false ,
162
129
},
163
130
"node_pools" : {
164
131
Type : schema .TypeSet ,
@@ -411,6 +378,7 @@ func resourceCluster() *schema.Resource {
411
378
"storage_config" : {
412
379
Type : schema .TypeList ,
413
380
Optional : true ,
381
+ Computed : true ,
414
382
MaxItems : 1 ,
415
383
Elem : & schema.Resource {
416
384
Schema : map [string ]* schema.Schema {
@@ -423,6 +391,7 @@ func resourceCluster() *schema.Resource {
423
391
names .AttrEnabled : {
424
392
Type : schema .TypeBool ,
425
393
Optional : true ,
394
+ Default : false ,
426
395
},
427
396
},
428
397
},
@@ -526,30 +495,25 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta any
526
495
name := d .Get (names .AttrName ).(string )
527
496
input := eks.CreateClusterInput {
528
497
BootstrapSelfManagedAddons : aws .Bool (d .Get ("bootstrap_self_managed_addons" ).(bool )),
498
+ ComputeConfig : expandComputeConfigRequest (d .Get ("compute_config" ).([]any )),
529
499
EncryptionConfig : expandEncryptionConfig (d .Get ("encryption_config" ).([]any )),
500
+ KubernetesNetworkConfig : expandKubernetesNetworkConfigRequest (d .Get ("kubernetes_network_config" ).([]any )),
530
501
Logging : expandLogging (d .Get ("enabled_cluster_log_types" ).(* schema.Set )),
531
502
Name : aws .String (name ),
532
503
ResourcesVpcConfig : expandVpcConfigRequest (d .Get (names .AttrVPCConfig ).([]any )),
533
504
RoleArn : aws .String (d .Get (names .AttrRoleARN ).(string )),
505
+ StorageConfig : expandStorageConfigRequest (d .Get ("storage_config" ).([]any )),
534
506
Tags : getTagsIn (ctx ),
535
507
}
536
508
537
509
if v , ok := d .GetOk ("access_config" ); ok {
538
510
input .AccessConfig = expandCreateAccessConfigRequest (v .([]any ))
539
511
}
540
512
541
- if v , ok := d .GetOk ("compute_config" ); ok {
542
- input .ComputeConfig = expandComputeConfigRequest (v .([]any ))
543
- }
544
-
545
513
if v , ok := d .GetOk (names .AttrDeletionProtection ); ok {
546
514
input .DeletionProtection = aws .Bool (v .(bool ))
547
515
}
548
516
549
- if v , ok := d .GetOk ("kubernetes_network_config" ); ok {
550
- input .KubernetesNetworkConfig = expandKubernetesNetworkConfigRequest (v .([]any ))
551
- }
552
-
553
517
if v , ok := d .GetOk ("outpost_config" ); ok {
554
518
input .OutpostConfig = expandOutpostConfigRequest (v .([]any ))
555
519
}
@@ -558,10 +522,6 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta any
558
522
input .RemoteNetworkConfig = expandCreateRemoteNetworkConfigRequest (v .([]any ))
559
523
}
560
524
561
- if v , ok := d .GetOk ("storage_config" ); ok {
562
- input .StorageConfig = expandStorageConfigRequest (v .([]any ))
563
- }
564
-
565
525
if v , ok := d .GetOk ("upgrade_policy" ); ok {
566
526
input .UpgradePolicy = expandUpgradePolicy (v .([]any ))
567
527
}
@@ -755,10 +715,15 @@ func resourceClusterUpdate(ctx context.Context, d *schema.ResourceData, meta any
755
715
}
756
716
}
757
717
718
+ // All three fields are required to enable/disable Auto Mode or else you receive the error:
719
+ // InvalidParameterException: For EKS Auto Mode, please ensure that all required configs,
720
+ // including computeConfig, kubernetesNetworkConfig, and blockStorage are all either fully enabled or fully disabled.
721
+ // In addition, when updating other Auto Mode arguments (i.e. - computeConfig.nodePools/nodeRoleARN), all 3 fields are required
758
722
if d .HasChanges ("compute_config" , "kubernetes_network_config" , "storage_config" ) {
759
723
computeConfig := expandComputeConfigRequest (d .Get ("compute_config" ).([]any ))
760
724
kubernetesNetworkConfig := expandKubernetesNetworkConfigRequest (d .Get ("kubernetes_network_config" ).([]any ))
761
725
storageConfig := expandStorageConfigRequest (d .Get ("storage_config" ).([]any ))
726
+
762
727
input := eks.UpdateClusterConfigInput {
763
728
ComputeConfig : computeConfig ,
764
729
KubernetesNetworkConfig : kubernetesNetworkConfig ,
@@ -769,13 +734,13 @@ func resourceClusterUpdate(ctx context.Context, d *schema.ResourceData, meta any
769
734
output , err := conn .UpdateClusterConfig (ctx , & input )
770
735
771
736
if err != nil {
772
- return sdkdiag .AppendErrorf (diags , "updating EKS Cluster (%s) compute config : %s" , d .Id (), err )
737
+ return sdkdiag .AppendErrorf (diags , "updating EKS Cluster (%s) Auto Mode settings : %s" , d .Id (), err )
773
738
}
774
739
775
740
updateID := aws .ToString (output .Update .Id )
776
741
777
742
if _ , err = waitClusterUpdateSuccessful (ctx , conn , d .Id (), updateID , d .Timeout (schema .TimeoutUpdate )); err != nil {
778
- return sdkdiag .AppendErrorf (diags , "waiting for EKS Cluster (%s) compute config update (%s): %s" , d .Id (), updateID , err )
743
+ return sdkdiag .AppendErrorf (diags , "waiting for EKS Cluster (%s) Auto Mode settings update (%s): %s" , d .Id (), updateID , err )
779
744
}
780
745
}
781
746
@@ -1145,7 +1110,7 @@ func waitClusterDeleted(ctx context.Context, conn *eks.Client, name string, time
1145
1110
return nil , err
1146
1111
}
1147
1112
1148
- func waitClusterUpdateSuccessful (ctx context.Context , conn * eks.Client , name , id string , timeout time.Duration ) (* types.Update , error ) { //nolint:unparam
1113
+ func waitClusterUpdateSuccessful (ctx context.Context , conn * eks.Client , name , id string , timeout time.Duration ) (* types.Update , error ) {
1149
1114
stateConf := & retry.StateChangeConf {
1150
1115
Pending : enum .Slice (types .UpdateStatusInProgress ),
1151
1116
Target : enum .Slice (types .UpdateStatusSuccessful ),
@@ -1209,17 +1174,21 @@ func expandUpdateAccessConfigRequest(tfList []any) *types.UpdateAccessConfigRequ
1209
1174
}
1210
1175
1211
1176
func expandComputeConfigRequest (tfList []any ) * types.ComputeConfigRequest {
1177
+ apiObject := & types.ComputeConfigRequest {}
1178
+
1212
1179
if len (tfList ) == 0 {
1213
- return nil
1180
+ // Ensure this is always present to avoid the error:
1181
+ // InvalidParameterException: The type for cluster update was not provided.
1182
+ // when the field is removed (nil)
1183
+ apiObject .Enabled = aws .Bool (false )
1184
+ return apiObject
1214
1185
}
1215
1186
1216
1187
tfMap , ok := tfList [0 ].(map [string ]any )
1217
1188
if ! ok {
1218
1189
return nil
1219
1190
}
1220
1191
1221
- apiObject := & types.ComputeConfigRequest {}
1222
-
1223
1192
if v , ok := tfMap [names .AttrEnabled ].(bool ); ok {
1224
1193
apiObject .Enabled = aws .Bool (v )
1225
1194
}
@@ -1282,17 +1251,23 @@ func expandProvider(tfList []any) *types.Provider {
1282
1251
}
1283
1252
1284
1253
func expandStorageConfigRequest (tfList []any ) * types.StorageConfigRequest {
1254
+ apiObject := & types.StorageConfigRequest {}
1255
+
1285
1256
if len (tfList ) == 0 {
1286
- return nil
1257
+ // Ensure this is always present to avoid the error:
1258
+ // InvalidParameterException: The type for cluster update was not provided.
1259
+ // when the field is removed (nil)
1260
+ apiObject .BlockStorage = & types.BlockStorage {
1261
+ Enabled : aws .Bool (false ),
1262
+ }
1263
+ return apiObject
1287
1264
}
1288
1265
1289
1266
tfMap , ok := tfList [0 ].(map [string ]any )
1290
1267
if ! ok {
1291
1268
return nil
1292
1269
}
1293
1270
1294
- apiObject := & types.StorageConfigRequest {}
1295
-
1296
1271
if v , ok := tfMap ["block_storage" ].([]any ); ok {
1297
1272
apiObject .BlockStorage = expandBlockStorage (v )
1298
1273
}
@@ -1365,7 +1340,7 @@ func expandControlPlanePlacementRequest(tfList []any) *types.ControlPlanePlaceme
1365
1340
return apiObject
1366
1341
}
1367
1342
1368
- func expandVpcConfigRequest (tfList []any ) * types.VpcConfigRequest { // nosemgrep:ci.caps5-in-func-name
1343
+ func expandVpcConfigRequest (tfList []any ) * types.VpcConfigRequest {
1369
1344
if len (tfList ) == 0 {
1370
1345
return nil
1371
1346
}
@@ -1390,17 +1365,24 @@ func expandVpcConfigRequest(tfList []any) *types.VpcConfigRequest { // nosemgrep
1390
1365
}
1391
1366
1392
1367
func expandKubernetesNetworkConfigRequest (tfList []any ) * types.KubernetesNetworkConfigRequest {
1368
+ apiObject := & types.KubernetesNetworkConfigRequest {}
1369
+
1393
1370
if len (tfList ) == 0 {
1394
- return nil
1371
+ // Required to avoid the error:
1372
+ // InvalidParameterException: For EKS Auto Mode, please ensure that all required configs,
1373
+ // including computeConfig, kubernetesNetworkConfig, and blockStorage are all either fully enabled or fully disabled.
1374
+ // since the other two fields have been injected with `enabled: false` when the field is not present
1375
+ apiObject .ElasticLoadBalancing = & types.ElasticLoadBalancing {
1376
+ Enabled : aws .Bool (false ),
1377
+ }
1378
+ return apiObject
1395
1379
}
1396
1380
1397
1381
tfMap , ok := tfList [0 ].(map [string ]any )
1398
1382
if ! ok {
1399
1383
return nil
1400
1384
}
1401
1385
1402
- apiObject := & types.KubernetesNetworkConfigRequest {}
1403
-
1404
1386
if v , ok := tfMap ["elastic_load_balancing" ].([]any ); ok {
1405
1387
apiObject .ElasticLoadBalancing = expandKubernetesNetworkConfigElasticLoadBalancing (v )
1406
1388
}
@@ -1479,6 +1461,7 @@ func expandUpdateRemoteNetworkConfigRequest(tfList []any) *types.RemoteNetworkCo
1479
1461
1480
1462
return apiObject
1481
1463
}
1464
+
1482
1465
func expandRemoteNodeNetworks (tfList []any ) []types.RemoteNodeNetwork {
1483
1466
var apiObjects = []types.RemoteNodeNetwork {}
1484
1467
@@ -1681,7 +1664,7 @@ func flattenProvider(apiObject *types.Provider) []any {
1681
1664
return []any {tfMap }
1682
1665
}
1683
1666
1684
- func flattenVPCConfigResponse (vpcConfig * types.VpcConfigResponse ) []map [string ]any { // nosemgrep:ci.caps5-in-func-name
1667
+ func flattenVPCConfigResponse (vpcConfig * types.VpcConfigResponse ) []map [string ]any {
1685
1668
if vpcConfig == nil {
1686
1669
return []map [string ]any {}
1687
1670
}
@@ -1885,3 +1868,43 @@ func validateAutoModeCustomizeDiff(_ context.Context, d *schema.ResourceDiff, _
1885
1868
1886
1869
return nil
1887
1870
}
1871
+
1872
+ // Allow setting `compute_config.node_role_arn` to `null` when disabling auto mode or
1873
+ // built-in node pools without forcing re-creation of the cluster
1874
+ func validateAutoModeComputeConfigCustomizeDiff (_ context.Context , diff * schema.ResourceDiff , _ any ) error {
1875
+ if diff .Id () == "" {
1876
+ return nil
1877
+ }
1878
+
1879
+ oldValue , newValue := diff .GetChange ("compute_config" )
1880
+
1881
+ oldComputeConfig := expandComputeConfigRequest (oldValue .([]any ))
1882
+ newComputeConfig := expandComputeConfigRequest (newValue .([]any ))
1883
+
1884
+ if newComputeConfig == nil || oldComputeConfig == nil {
1885
+ return nil
1886
+ }
1887
+
1888
+ oldRoleARN := aws .ToString (oldComputeConfig .NodeRoleArn )
1889
+ newRoleARN := aws .ToString (newComputeConfig .NodeRoleArn )
1890
+
1891
+ newComputeConfigEnabled := aws .ToBool (newComputeConfig .Enabled )
1892
+
1893
+ // Do not force new if auto mode is disabled in new config and role ARN is unset
1894
+ if ! newComputeConfigEnabled && newRoleARN == "" {
1895
+ return nil
1896
+ }
1897
+
1898
+ // Do not force new if built-in node pools are zeroed in new config and role ARN is unset
1899
+ if len (newComputeConfig .NodePools ) == 0 && newRoleARN == "" {
1900
+ return nil
1901
+ }
1902
+
1903
+ // only force new if an existing role has changed, not if a new role is added
1904
+ if oldRoleARN != "" && oldRoleARN != newRoleARN {
1905
+ if err := diff .ForceNew ("compute_config.0.node_role_arn" ); err != nil {
1906
+ return err
1907
+ }
1908
+ }
1909
+ return nil
1910
+ }
0 commit comments