@@ -230,7 +230,6 @@ func ResourceRedisCloudProDatabase() *schema.Resource {
230230 Type : schema .TypeString ,
231231 Optional : true ,
232232 Computed : true ,
233- ForceNew : true ,
234233 ValidateFunc : func (val interface {}, key string ) (warns []string , errs []error ) {
235234 v := val .(string )
236235 matched , err := regexp .MatchString (`^([2468])x$` , v )
@@ -251,8 +250,9 @@ func ResourceRedisCloudProDatabase() *schema.Resource {
251250 ConfigMode : schema .SchemaConfigModeAttr ,
252251 Optional : true ,
253252 // The API doesn't allow updating/delete modules. Unless we recreate the database.
254- ForceNew : true ,
255- MinItems : 1 ,
253+ ForceNew : true ,
254+ MinItems : 1 ,
255+ DiffSuppressFunc : modulesDiffSuppressFunc ,
256256 Elem : & schema.Resource {
257257 Schema : map [string ]* schema.Schema {
258258 "name" : {
@@ -418,6 +418,17 @@ func resourceRedisCloudProDatabaseCreate(ctx context.Context, d *schema.Resource
418418 createDatabase .RedisVersion = s
419419 })
420420
421+ // Warn if modules are explicitly configured for Redis 8.0+
422+ var diags diag.Diagnostics
423+ redisVersion := d .Get ("redis_version" ).(string )
424+ if shouldWarnRedis8Modules (redisVersion , len (createModules ) > 0 ) {
425+ diags = append (diags , diag.Diagnostic {
426+ Severity : diag .Warning ,
427+ Summary : "Modules are bundled by default in Redis 8.0+" ,
428+ Detail : fmt .Sprintf ("The 'modules' block is deprecated for Redis %s and later versions, as modules (RediSearch, RedisJSON, RedisBloom, RedisTimeSeries) are bundled by default. You should remove the 'modules' block from your configuration." , redisVersion ),
429+ })
430+ }
431+
421432 utils .SetStringIfNotEmpty (d , "password" , func (s * string ) {
422433 createDatabase .Password = s
423434 })
@@ -449,31 +460,32 @@ func resourceRedisCloudProDatabaseCreate(ctx context.Context, d *schema.Resource
449460 // Confirm sub is ready to accept a db request
450461 if err := utils .WaitForSubscriptionToBeActive (ctx , subId , api ); err != nil {
451462 utils .SubscriptionMutex .Unlock (subId )
452- return diag .FromErr (err )
463+ return append ( diags , diag .FromErr (err ) ... )
453464 }
454465
455466 dbId , err := api .Client .Database .Create (ctx , subId , createDatabase )
456467 if err != nil {
457468 utils .SubscriptionMutex .Unlock (subId )
458- return diag .FromErr (err )
469+ return append ( diags , diag .FromErr (err ) ... )
459470 }
460471
461472 d .SetId (utils .BuildResourceId (subId , dbId ))
462473
463474 // Confirm db + sub active status
464475 if err := utils .WaitForDatabaseToBeActive (ctx , subId , dbId , api ); err != nil {
465476 utils .SubscriptionMutex .Unlock (subId )
466- return diag .FromErr (err )
477+ return append ( diags , diag .FromErr (err ) ... )
467478 }
468479 if err := utils .WaitForSubscriptionToBeActive (ctx , subId , api ); err != nil {
469480 utils .SubscriptionMutex .Unlock (subId )
470- return diag .FromErr (err )
481+ return append ( diags , diag .FromErr (err ) ... )
471482 }
472483
473484 // Some attributes on a database are not accessible by the subscription creation API.
474485 // Run the subscription update function to apply any additional changes to the databases, such as password, enableDefaultUser and so on.
475486 utils .SubscriptionMutex .Unlock (subId )
476- return resourceRedisCloudProDatabaseUpdate (ctx , d , meta )
487+ updateDiags := resourceRedisCloudProDatabaseUpdate (ctx , d , meta )
488+ return append (diags , updateDiags ... )
477489}
478490
479491func resourceRedisCloudProDatabaseRead (ctx context.Context , d * schema.ResourceData , meta interface {}) diag.Diagnostics {
@@ -559,7 +571,7 @@ func resourceRedisCloudProDatabaseRead(ctx context.Context, d *schema.ResourceDa
559571 // For Redis 8.0+, modules are bundled by default and returned by the API
560572 // Only set modules in state if they were explicitly defined in the config
561573 redisVersion := redis .StringValue (db .RedisVersion )
562- if redisVersion >= "8.0" {
574+ if shouldSuppressModuleDiffsForRedis8 ( redisVersion ) {
563575 // Only set modules if they were explicitly configured by the user
564576 if _ , ok := d .GetOk ("modules" ); ok {
565577 if err := d .Set ("modules" , FlattenModules (db .Modules )); err != nil {
@@ -714,6 +726,7 @@ func resourceRedisCloudProDatabaseDelete(ctx context.Context, d *schema.Resource
714726
715727func resourceRedisCloudProDatabaseUpdate (ctx context.Context , d * schema.ResourceData , meta interface {}) diag.Diagnostics {
716728 api := meta .(* client.ApiClient )
729+ var diags diag.Diagnostics
717730
718731 _ , dbId , err := ToDatabaseId (d .Id ())
719732 if err != nil {
@@ -821,7 +834,7 @@ func resourceRedisCloudProDatabaseUpdate(ctx context.Context, d *schema.Resource
821834 update .ClientSSLCertificate = redis .String (clientSSLCertificate )
822835 } else if len (clientTLSCertificates ) > 0 {
823836 utils .SubscriptionMutex .Unlock (subId )
824- return diag .Errorf ("TLS certificates may not be provided while enable_tls is false" )
837+ return append ( diags , diag .Errorf ("TLS certificates may not be provided while enable_tls is false" ) ... )
825838 } else {
826839 // Default: enable_tls=false, client_ssl_certificate=""
827840 update .EnableTls = redis .Bool (enableTLS )
@@ -845,14 +858,25 @@ func resourceRedisCloudProDatabaseUpdate(ctx context.Context, d *schema.Resource
845858 update .RespVersion = redis .String (respVersion )
846859 }
847860
861+ // Warn if modules are explicitly configured for Redis 8.0+
862+ redisVersion := d .Get ("redis_version" ).(string )
863+ modules := d .Get ("modules" ).(* schema.Set )
864+ if shouldWarnRedis8Modules (redisVersion , modules .Len () > 0 ) {
865+ diags = append (diags , diag.Diagnostic {
866+ Severity : diag .Warning ,
867+ Summary : "Modules are bundled by default in Redis 8.0+" ,
868+ Detail : fmt .Sprintf ("The 'modules' block is deprecated for Redis %s and later versions, as modules (RediSearch, RedisJSON, RedisBloom, RedisTimeSeries) are bundled by default. You should remove the 'modules' block from your configuration." , redisVersion ),
869+ })
870+ }
871+
848872 // Confirm sub + db are ready to accept a db request
849873 if err := utils .WaitForSubscriptionToBeActive (ctx , subId , api ); err != nil {
850874 utils .SubscriptionMutex .Unlock (subId )
851- return diag .FromErr (err )
875+ return append ( diags , diag .FromErr (err ) ... )
852876 }
853877 if err := utils .WaitForDatabaseToBeActive (ctx , subId , dbId , api ); err != nil {
854878 utils .SubscriptionMutex .Unlock (subId )
855- return diag .FromErr (err )
879+ return append ( diags , diag .FromErr (err ) ... )
856880 }
857881
858882 // if redis_version has changed, then upgrade first
@@ -863,11 +887,11 @@ func resourceRedisCloudProDatabaseUpdate(ctx context.Context, d *schema.Resource
863887 // if either version is blank, it could attempt to upgrade unnecessarily.
864888 // only upgrade when a known version goes to another known version
865889 if originalVersion .(string ) != "" && newVersion .(string ) != "" {
866- if diags , unlocked := upgradeRedisVersion (ctx , api , subId , dbId , newVersion .(string )); diags != nil {
890+ if upgradeDiags , unlocked := upgradeRedisVersion (ctx , api , subId , dbId , newVersion .(string )); upgradeDiags != nil {
867891 if ! unlocked {
868892 utils .SubscriptionMutex .Unlock (subId )
869893 }
870- return diags
894+ return append ( diags , upgradeDiags ... )
871895 }
872896 }
873897 }
@@ -876,26 +900,27 @@ func resourceRedisCloudProDatabaseUpdate(ctx context.Context, d *schema.Resource
876900
877901 if err := api .Client .Database .Update (ctx , subId , dbId , update ); err != nil {
878902 utils .SubscriptionMutex .Unlock (subId )
879- return diag .FromErr (err )
903+ return append ( diags , diag .FromErr (err ) ... )
880904 }
881905
882906 // Confirm db + sub active status
883907 if err := utils .WaitForDatabaseToBeActive (ctx , subId , dbId , api ); err != nil {
884908 utils .SubscriptionMutex .Unlock (subId )
885- return diag .FromErr (err )
909+ return append ( diags , diag .FromErr (err ) ... )
886910 }
887911 if err := utils .WaitForSubscriptionToBeActive (ctx , subId , api ); err != nil {
888912 utils .SubscriptionMutex .Unlock (subId )
889- return diag .FromErr (err )
913+ return append ( diags , diag .FromErr (err ) ... )
890914 }
891915
892916 // The Tags API is synchronous so we shouldn't have to wait for anything
893917 if err := WriteTags (ctx , api , subId , dbId , d ); err != nil {
894- return diag .FromErr (err )
918+ return append ( diags , diag .FromErr (err ) ... )
895919 }
896920
897921 utils .SubscriptionMutex .Unlock (subId )
898- return resourceRedisCloudProDatabaseRead (ctx , d , meta )
922+ readDiags := resourceRedisCloudProDatabaseRead (ctx , d , meta )
923+ return append (diags , readDiags ... )
899924}
900925
901926func upgradeRedisVersion (ctx context.Context , api * client.ApiClient , subId int , dbId int , newVersion string ) (diag.Diagnostics , bool ) {
@@ -1068,19 +1093,49 @@ func shouldWarnRedis8Modules(version string, hasModules bool) bool {
10681093 return false
10691094}
10701095
1096+ // shouldSuppressModuleDiffsForRedis8 checks if module diffs should be suppressed for Redis 8.0 or higher
1097+ // In Redis 8.0+, modules are bundled by default, so we should ignore changes to explicitly configured modules
1098+ func shouldSuppressModuleDiffsForRedis8 (version string ) bool {
1099+ if len (version ) == 0 {
1100+ return false
1101+ }
1102+ majorVersionStr := strings .Split (version , "." )[0 ]
1103+ if majorVersion , err := strconv .Atoi (majorVersionStr ); err == nil {
1104+ return majorVersion >= 8
1105+ }
1106+ return false
1107+ }
1108+
1109+ // modulesDiffSuppressFunc returns a DiffSuppressFunc that suppresses module diffs for Redis 8.0+
1110+ // This prevents Terraform from showing module changes as "forces replacement" when upgrading to Redis 8.0+
1111+ func modulesDiffSuppressFunc (k , oldValue , newValue string , d * schema.ResourceData ) bool {
1112+ redisVersion , ok := d .GetOk ("redis_version" )
1113+ if ! ok {
1114+ return false
1115+ }
1116+ version := redisVersion .(string )
1117+ return shouldSuppressModuleDiffsForRedis8 (version )
1118+ }
1119+
10711120func validateModulesForRedis8 () schema.CustomizeDiffFunc {
10721121 return func (ctx context.Context , diff * schema.ResourceDiff , meta interface {}) error {
1073- redisVersion , versionExists := diff .GetOk ("redis_version" )
1074- modules , modulesExists := diff .GetOkExists ("modules" )
1122+ // Check if modules are configured for Redis 8.0+
1123+ redisVersionRaw , ok := diff .GetOk ("redis_version" )
1124+ if ! ok {
1125+ return nil
1126+ }
1127+ redisVersion := redisVersionRaw .(string )
10751128
1076- if versionExists && modulesExists {
1077- version := redisVersion .(string )
1078- moduleSet := modules .(* schema.Set )
1129+ modulesRaw , ok := diff .GetOk ("modules" )
1130+ if ! ok {
1131+ return nil
1132+ }
1133+ modules := modulesRaw .(* schema.Set )
10791134
1080- if shouldWarnRedis8Modules (version , moduleSet .Len () > 0 ) {
1081- log .Printf ("[WARN] Modules are bundled by default in Redis %s. You should remove the modules block as it is deprecated for this version." , version )
1082- }
1135+ if shouldWarnRedis8Modules (redisVersion , modules .Len () > 0 ) {
1136+ log .Printf ("[WARN] Modules are bundled by default in Redis %s and later versions. The 'modules' block is deprecated for Redis 8.0+ as modules (RediSearch, RedisJSON, RedisBloom, RedisTimeSeries) are bundled by default. You should remove the 'modules' block from your configuration." , redisVersion )
10831137 }
1138+
10841139 return nil
10851140 }
10861141}
0 commit comments