@@ -2,6 +2,7 @@ package utils
2
2
3
3
import (
4
4
"bytes"
5
+ "context"
5
6
"encoding/base64"
6
7
"encoding/json"
7
8
"fmt"
@@ -12,10 +13,26 @@ import (
12
13
"strings"
13
14
"time"
14
15
16
+ "github.com/hashicorp/go-multierror"
15
17
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
16
18
awspolicy "github.com/jen20/awspolicyequivalence"
17
19
)
18
20
21
+ // ComposeAnyCustomDiffFunc allows parameters to determine multiple customDiff methods.
22
+ // When any method (CustomizeDiffFunc) returns an error, this compose function will record this error and return finally.
23
+ func ComposeAnyCustomDiffFunc (fs ... schema.CustomizeDiffFunc ) schema.CustomizeDiffFunc {
24
+ return func (ctx context.Context , d * schema.ResourceDiff , meta interface {}) error {
25
+ var mErr * multierror.Error
26
+
27
+ for _ , f := range fs {
28
+ if err := f (ctx , d , meta ); err != nil {
29
+ mErr = multierror .Append (mErr , err )
30
+ }
31
+ }
32
+ return mErr .ErrorOrNil ()
33
+ }
34
+ }
35
+
19
36
// ComposeAnySchemaDiffSuppressFunc allows parameters to determine multiple Diff methods.
20
37
// When any method (SchemaDiffSuppressFunc) returns true, this compose function will return true.
21
38
// It will only return false when all methods (SchemaDiffSuppressFunc) return false.
@@ -319,39 +336,130 @@ func diffObjectParam(paramKey, _, _ string, d *schema.ResourceData) bool {
319
336
320
337
func SuppressMapDiffs () schema.SchemaDiffSuppressFunc {
321
338
return func (paramKey , o , n string , d * schema.ResourceData ) bool {
339
+ log .Printf ("[DEBUG] SuppressMapDiffs: called with paramKey='%s', old='%s', new='%s'" , paramKey , o , n )
340
+
341
+ // Ignore length change judgment, because this method will judge each changed key one by one
322
342
if strings .HasSuffix (paramKey , ".%" ) {
323
- // Ignore the length judgment, because this method will judge each changed key one by one.
343
+ log . Printf ( "[DEBUG] SuppressMapDiffs: ignoring length change for '%s'" , paramKey )
324
344
return true
325
345
}
326
- if n != "" {
327
- log .Printf ("[DEBUG] The new value is found and report this change directly, the value is: %s" , n )
328
- // When the new value is not empty and the key is in the *terraform.InstanceDiff.Attributes list, it means
329
- // that the value has been modified compared to the value returned by the console, report this change
330
- // directly.
346
+
347
+ // Handle the case where the entire map is being changed
348
+ if ! strings .Contains (paramKey , "." ) {
349
+ return suppressEntireMapDiff (paramKey , d )
350
+ }
351
+
352
+ // Handle single key changes
353
+ return suppressSingleKeyDiff (paramKey , d )
354
+ }
355
+ }
356
+
357
+ // suppressEntireMapDiff handles changes to the entire map
358
+ func suppressEntireMapDiff (paramKey string , d * schema.ResourceData ) bool {
359
+ originMapCategory := fmt .Sprintf ("%s_origin" , paramKey )
360
+ log .Printf ("[DEBUG] SuppressMapDiffs: handling entire map change for '%s', origin map category: '%s'" ,
361
+ paramKey , originMapCategory )
362
+
363
+ originMapVal := d .Get (originMapCategory )
364
+ if originMapVal == nil {
365
+ log .Printf ("[DEBUG] SuppressMapDiffs: origin map '%s' is nil, suppressing diff for entire map '%s'" ,
366
+ originMapCategory , paramKey )
367
+ return true
368
+ }
369
+
370
+ originMap := TryMapValueAnalysis (originMapVal )
371
+ if len (originMap ) == 0 {
372
+ log .Printf ("[DEBUG] SuppressMapDiffs: origin map '%s' is empty, suppressing diff for entire map '%s'" ,
373
+ originMapCategory , paramKey )
374
+ return true
375
+ }
376
+
377
+ // For entire map changes, we need to check if all keys in the new value exist in origin
378
+ // This is a simplified approach - in practice, you might want more sophisticated comparison
379
+ log .Printf ("[DEBUG] SuppressMapDiffs: entire map '%s' change detected, checking against origin" , paramKey )
380
+ return false // For now, report the change and let individual key suppression handle it
381
+ }
382
+
383
+ // suppressSingleKeyDiff handles changes to a single key
384
+ func suppressSingleKeyDiff (paramKey string , d * schema.ResourceData ) bool {
385
+ categories := strings .Split (paramKey , "." )
386
+ mapCategory := strings .Join (categories [:len (categories )- 1 ], "." )
387
+ originMapCategory := fmt .Sprintf ("%s_origin" , mapCategory )
388
+ keyName := categories [len (categories )- 1 ]
389
+
390
+ log .Printf ("[DEBUG] SuppressMapDiffs: processing key '%s', mapCategory='%s', originMapCategory='%s', keyName='%s'" ,
391
+ paramKey , mapCategory , originMapCategory , keyName )
392
+
393
+ // Get origin map (last local configuration)
394
+ originMapVal := d .Get (originMapCategory )
395
+ originMap := TryMapValueAnalysis (originMapVal )
396
+ log .Printf ("[DEBUG] SuppressMapDiffs: origin map '%s' content: %+v" , originMapCategory , originMap )
397
+
398
+ // Get current configuration map
399
+ currentMapVal := d .Get (mapCategory )
400
+ if currentMapVal == nil {
401
+ log .Printf ("[DEBUG] SuppressMapDiffs: current map '%s' is nil, suppressing diff for key '%s'" ,
402
+ mapCategory , keyName )
403
+ return true
404
+ }
405
+
406
+ currentMap := TryMapValueAnalysis (currentMapVal )
407
+ log .Printf ("[DEBUG] SuppressMapDiffs: current map '%s' content: %+v" , mapCategory , currentMap )
408
+
409
+ // Check if the key exists in current configuration
410
+ existsInCurrent := keyExists (currentMap , keyName )
411
+ existsInOrigin := keyExists (originMap , keyName )
412
+ isOriginEmpty := originMapVal == nil || len (originMap ) == 0
413
+
414
+ // Determine suppression based on key existence
415
+ return determineSuppression (existsInCurrent , existsInOrigin , isOriginEmpty , keyName )
416
+ }
417
+
418
+ // keyExists checks if a key exists in the map
419
+ func keyExists (m map [string ]interface {}, key string ) bool {
420
+ _ , exists := m [key ]
421
+ return exists
422
+ }
423
+
424
+ // determineSuppression determines whether to suppress the diff based on key existence
425
+ func determineSuppression (existsInCurrent , existsInOrigin , isOriginEmpty bool , keyName string ) bool {
426
+ if existsInCurrent {
427
+ // The key exists in current configuration
428
+ if isOriginEmpty {
429
+ // Origin is empty or nil, report the change (locally added)
430
+ log .Printf ("[DEBUG][SuppressMapDiffs] The key '%s' found in current config but origin is empty" , keyName )
331
431
return false
332
432
}
333
433
334
- var (
335
- // The absolute path of the current key.
336
- categories = strings .Split (paramKey , "." )
337
- mapCategory = strings .Join (categories [:len (categories )- 1 ], "." )
338
- originMapCategory = fmt .Sprintf ("%s_origin" , mapCategory )
339
- keyName = categories [len (categories )- 1 ]
340
- )
341
-
342
- originMap , ok := d .Get (originMapCategory ).(map [string ]interface {})
343
- if ! ok {
344
- log .Printf ("[WARN] Unable to find corresponding origin parameter (%s) in current category, please check your schema definition" ,
345
- originMapCategory )
434
+ if existsInOrigin {
435
+ // The key exists in both current config and origin, report this change
436
+ log .Printf ("[DEBUG][SuppressMapDiffs] The key '%s' found in both current config and origin" , keyName )
437
+ return false
438
+ } else {
439
+ // The key exists in current config but not in origin (locally added)
440
+ log .Printf ("[DEBUG][SuppressMapDiffs] The key '%s' found in current config but not in origin" , keyName )
441
+ return false
442
+ }
443
+ } else {
444
+ // The key does not exist in current configuration
445
+ if isOriginEmpty {
446
+ // Origin is empty or nil, suppress the diff (remotely added)
447
+ log .Printf ("[DEBUG][SuppressMapDiffs] The key '%s' not found in current config and origin is empty, suppressing diff" ,
448
+ keyName )
346
449
return true
347
450
}
348
451
349
- if _ , ok := originMap [keyName ]; ok {
350
- // The key is found in the origin parameter value and report this change directly.
452
+ if existsInOrigin {
453
+ // The key exists in origin but not in current config (locally removed)
454
+ log .Printf ("[DEBUG][SuppressMapDiffs] The key '%s' found in origin but not in current config (locally removed)" ,
455
+ keyName )
351
456
return false
457
+ } else {
458
+ // The key does not exist in either current config or origin (remotely added)
459
+ log .Printf ("[DEBUG][SuppressMapDiffs] The key '%s' not found in either current config or origin (remotely added), suppressing diff" ,
460
+ keyName )
461
+ return true
352
462
}
353
- // The relevant value is not configured locally, and the change is ignored.
354
- return true
355
463
}
356
464
}
357
465
0 commit comments