@@ -402,16 +402,10 @@ func schemaNodeConfig() *schema.Schema {
402
402
},
403
403
404
404
"taint" : {
405
- Type : schema .TypeList ,
406
- Optional : true ,
407
- // Computed=true because GKE Sandbox will automatically add taints to nodes that can/cannot run sandboxed pods.
408
- Computed : true ,
409
- ForceNew : true ,
410
- // Legacy config mode allows explicitly defining an empty taint.
411
- // See https://www.terraform.io/docs/configuration/attr-as-blocks.html
412
- ConfigMode : schema .SchemaConfigModeAttr ,
413
- Description : `List of Kubernetes taints to be applied to each node.` ,
414
- DiffSuppressFunc : containerNodePoolTaintSuppress ,
405
+ Type : schema .TypeList ,
406
+ Optional : true ,
407
+ ForceNew : true ,
408
+ Description : `List of Kubernetes taints to be applied to each node.` ,
415
409
Elem : & schema.Resource {
416
410
Schema : map [string ]* schema.Schema {
417
411
"key" : {
@@ -437,6 +431,31 @@ func schemaNodeConfig() *schema.Schema {
437
431
},
438
432
},
439
433
434
+ "effective_taints" : {
435
+ Type : schema .TypeList ,
436
+ Computed : true ,
437
+ Description : `List of kubernetes taints applied to each node.` ,
438
+ Elem : & schema.Resource {
439
+ Schema : map [string ]* schema.Schema {
440
+ "key" : {
441
+ Type : schema .TypeString ,
442
+ Computed : true ,
443
+ Description : `Key for taint.` ,
444
+ },
445
+ "value" : {
446
+ Type : schema .TypeString ,
447
+ Computed : true ,
448
+ Description : `Value for taint.` ,
449
+ },
450
+ "effect" : {
451
+ Type : schema .TypeString ,
452
+ Computed : true ,
453
+ Description : `Effect for taint.` ,
454
+ },
455
+ },
456
+ },
457
+ },
458
+
440
459
"workload_metadata_config" : {
441
460
Computed : true ,
442
461
Type : schema .TypeList ,
@@ -880,8 +899,10 @@ func expandNodeConfig(v interface{}) *container.NodeConfig {
880
899
Value : data ["value" ].(string ),
881
900
Effect : data ["effect" ].(string ),
882
901
}
902
+
883
903
nodeTaints = append (nodeTaints , taint )
884
904
}
905
+
885
906
nc .Taints = nodeTaints
886
907
}
887
908
@@ -1071,13 +1092,24 @@ func flattenNodeConfigDefaults(c *container.NodeConfigDefaults) []map[string]int
1071
1092
return result
1072
1093
}
1073
1094
1074
- func flattenNodeConfig (c * container.NodeConfig ) []map [string ]interface {} {
1095
+ // v == old state of `node_config`
1096
+ func flattenNodeConfig (c * container.NodeConfig , v interface {}) []map [string ]interface {} {
1075
1097
config := make ([]map [string ]interface {}, 0 , 1 )
1076
1098
1077
1099
if c == nil {
1078
1100
return config
1079
1101
}
1080
1102
1103
+ // default to no prior taint state if there are any issues
1104
+ oldTaints := []interface {}{}
1105
+ oldNodeConfigSchemaContainer := v .([]interface {})
1106
+ if len (oldNodeConfigSchemaContainer ) != 0 {
1107
+ oldNodeConfigSchema := oldNodeConfigSchemaContainer [0 ].(map [string ]interface {})
1108
+ if vt , ok := oldNodeConfigSchema ["taint" ]; ok && len (vt .([]interface {})) > 0 {
1109
+ oldTaints = vt .([]interface {})
1110
+ }
1111
+ }
1112
+
1081
1113
config = append (config , map [string ]interface {}{
1082
1114
"machine_type" : c .MachineType ,
1083
1115
"disk_size_gb" : c .DiskSizeGb ,
@@ -1101,7 +1133,8 @@ func flattenNodeConfig(c *container.NodeConfig) []map[string]interface{} {
1101
1133
"spot" : c .Spot ,
1102
1134
"min_cpu_platform" : c .MinCpuPlatform ,
1103
1135
"shielded_instance_config" : flattenShieldedInstanceConfig (c .ShieldedInstanceConfig ),
1104
- "taint" : flattenTaints (c .Taints ),
1136
+ "taint" : flattenTaints (c .Taints , oldTaints ),
1137
+ "effective_taints" : flattenEffectiveTaints (c .Taints ),
1105
1138
"workload_metadata_config" : flattenWorkloadMetadataConfig (c .WorkloadMetadataConfig ),
1106
1139
"sandbox_config" : flattenSandboxConfig (c .SandboxConfig ),
1107
1140
"host_maintenance_policy" : flattenHostMaintenancePolicy (c .HostMaintenancePolicy ),
@@ -1241,7 +1274,31 @@ func flattenGKEReservationAffinity(c *container.ReservationAffinity) []map[strin
1241
1274
return result
1242
1275
}
1243
1276
1244
- func flattenTaints (c []* container.NodeTaint ) []map [string ]interface {} {
1277
+ // flattenTaints records the set of taints already present in state.
1278
+ func flattenTaints (c []* container.NodeTaint , oldTaints []interface {}) []map [string ]interface {} {
1279
+ taintKeys := map [string ]struct {}{}
1280
+ for _ , raw := range oldTaints {
1281
+ data := raw .(map [string ]interface {})
1282
+ taintKey := data ["key" ].(string )
1283
+ taintKeys [taintKey ] = struct {}{}
1284
+ }
1285
+
1286
+ result := []map [string ]interface {}{}
1287
+ for _ , taint := range c {
1288
+ if _ , ok := taintKeys [taint .Key ]; ok {
1289
+ result = append (result , map [string ]interface {}{
1290
+ "key" : taint .Key ,
1291
+ "value" : taint .Value ,
1292
+ "effect" : taint .Effect ,
1293
+ })
1294
+ }
1295
+ }
1296
+
1297
+ return result
1298
+ }
1299
+
1300
+ // flattenEffectiveTaints records the complete set of taints returned from GKE.
1301
+ func flattenEffectiveTaints (c []* container.NodeTaint ) []map [string ]interface {} {
1245
1302
result := []map [string ]interface {}{}
1246
1303
for _ , taint := range c {
1247
1304
result = append (result , map [string ]interface {}{
@@ -1250,6 +1307,7 @@ func flattenTaints(c []*container.NodeTaint) []map[string]interface{} {
1250
1307
"effect" : taint .Effect ,
1251
1308
})
1252
1309
}
1310
+
1253
1311
return result
1254
1312
}
1255
1313
@@ -1319,74 +1377,6 @@ func containerNodePoolLabelsSuppress(k, old, new string, d *schema.ResourceData)
1319
1377
return true
1320
1378
}
1321
1379
1322
- func containerNodePoolTaintSuppress (k , old , new string , d * schema.ResourceData ) bool {
1323
- // Node configs are embedded into multiple resources (container cluster and
1324
- // container node pool) so we determine the node config key dynamically.
1325
- idx := strings .Index (k , ".taint." )
1326
- if idx < 0 {
1327
- return false
1328
- }
1329
-
1330
- root := k [:idx ]
1331
-
1332
- // Right now, GKE only applies its own out-of-band labels when you enable
1333
- // Sandbox. We only need to perform diff suppression in this case;
1334
- // otherwise, the default Terraform behavior is fine.
1335
- o , n := d .GetChange (root + ".sandbox_config.0.sandbox_type" )
1336
- if o == nil || n == nil {
1337
- return false
1338
- }
1339
-
1340
- // Pull the entire changeset as a list rather than trying to deal with each
1341
- // element individually.
1342
- o , n = d .GetChange (root + ".taint" )
1343
- if o == nil || n == nil {
1344
- return false
1345
- }
1346
-
1347
- type taintType struct {
1348
- Key , Value , Effect string
1349
- }
1350
-
1351
- taintSet := make (map [taintType ]struct {})
1352
-
1353
- // Add all new taints to set.
1354
- for _ , raw := range n .([]interface {}) {
1355
- data := raw .(map [string ]interface {})
1356
- taint := taintType {
1357
- Key : data ["key" ].(string ),
1358
- Value : data ["value" ].(string ),
1359
- Effect : data ["effect" ].(string ),
1360
- }
1361
- taintSet [taint ] = struct {}{}
1362
- }
1363
-
1364
- // Remove all current taints, skipping GKE-managed keys if not present in
1365
- // the new configuration.
1366
- for _ , raw := range o .([]interface {}) {
1367
- data := raw .(map [string ]interface {})
1368
- taint := taintType {
1369
- Key : data ["key" ].(string ),
1370
- Value : data ["value" ].(string ),
1371
- Effect : data ["effect" ].(string ),
1372
- }
1373
- if _ , ok := taintSet [taint ]; ok {
1374
- delete (taintSet , taint )
1375
- } else if ! strings .HasPrefix (taint .Key , "sandbox.gke.io/" ) && taint .Key != "kubernetes.io/arch" {
1376
- // User-provided taint removed in new configuration.
1377
- return false
1378
- }
1379
- }
1380
-
1381
- // If, at this point, the set still has elements, the new configuration
1382
- // added an additional taint.
1383
- if len (taintSet ) > 0 {
1384
- return false
1385
- }
1386
-
1387
- return true
1388
- }
1389
-
1390
1380
func flattenKubeletConfig (c * container.NodeKubeletConfig ) []map [string ]interface {} {
1391
1381
result := []map [string ]interface {}{}
1392
1382
if c != nil {
0 commit comments