@@ -218,10 +218,11 @@ func ResourceIBMISInstance() *schema.Resource {
218
218
219
219
// cluster changes
220
220
"cluster_network_attachments" : & schema.Schema {
221
- Type : schema .TypeList ,
222
- Optional : true ,
223
- Computed : true ,
224
- Description : "The cluster network attachments for this virtual server instance.The cluster network attachments are ordered for consistent instance configuration." ,
221
+ Type : schema .TypeList ,
222
+ Optional : true ,
223
+ Computed : true ,
224
+ DiffSuppressFunc : diffSuppressClusterNetworkAttachment ,
225
+ Description : "The cluster network attachments for this virtual server instance.The cluster network attachments are ordered for consistent instance configuration." ,
225
226
Elem : & schema.Resource {
226
227
Schema : map [string ]* schema.Schema {
227
228
"cluster_network_interface" : & schema.Schema {
@@ -8151,3 +8152,254 @@ func setVolumePrototypesInState(d *schema.ResourceData, instance *vpcv1.Instance
8151
8152
8152
8153
return finalList , nil
8153
8154
}
8155
+
8156
+ // diffSuppressClusterNetworkAttachment handles comparing old and new cluster network attachments
8157
+ // to determine if there are actual changes that require an update
8158
+ func diffSuppressClusterNetworkAttachment (k , old , new string , d * schema.ResourceData ) bool {
8159
+ // If values are equal, no changes needed
8160
+ if old == new {
8161
+ return true
8162
+ }
8163
+
8164
+ // Get the lists of old and new attachments
8165
+ oldAttachments , newAttachments := []interface {}{}, []interface {}{}
8166
+ if v , ok := d .GetOk ("cluster_network_attachments" ); ok {
8167
+ newAttachments = v .([]interface {})
8168
+ }
8169
+ if v , ok := d .GetOk ("cluster_network_attachments" ); ok {
8170
+ oldAttachments = v .([]interface {})
8171
+ }
8172
+
8173
+ // If lengths differ, there are definitely changes
8174
+ if len (oldAttachments ) != len (newAttachments ) {
8175
+ return false
8176
+ }
8177
+
8178
+ // Compare each attachment
8179
+ for i := range oldAttachments {
8180
+ oldAttach := oldAttachments [i ].(map [string ]interface {})
8181
+ newAttach := newAttachments [i ].(map [string ]interface {})
8182
+
8183
+ // Compare cluster_network_interface
8184
+ oldInterface := oldAttach ["cluster_network_interface" ].([]interface {})[0 ].(map [string ]interface {})
8185
+ newInterface := newAttach ["cluster_network_interface" ].([]interface {})[0 ].(map [string ]interface {})
8186
+
8187
+ // Compare key properties
8188
+ if ! compareInterfaces (oldInterface , newInterface ) {
8189
+ return false
8190
+ }
8191
+ }
8192
+
8193
+ return true
8194
+ }
8195
+
8196
+ // compareInterfaces compares the key properties of cluster network interfaces
8197
+ func compareInterfaces (old , new map [string ]interface {}) bool {
8198
+ // Compare auto_delete
8199
+ if old ["auto_delete" ] != new ["auto_delete" ] {
8200
+ return false
8201
+ }
8202
+
8203
+ // Compare name
8204
+ if old ["name" ] != new ["name" ] {
8205
+ return false
8206
+ }
8207
+
8208
+ // Compare primary_ip
8209
+ oldPrimaryIP := old ["primary_ip" ].([]interface {})
8210
+ newPrimaryIP := new ["primary_ip" ].([]interface {})
8211
+ if len (oldPrimaryIP ) != len (newPrimaryIP ) {
8212
+ return false
8213
+ }
8214
+ if len (oldPrimaryIP ) > 0 {
8215
+ if ! comparePrimaryIP (oldPrimaryIP [0 ].(map [string ]interface {}), newPrimaryIP [0 ].(map [string ]interface {})) {
8216
+ return false
8217
+ }
8218
+ }
8219
+
8220
+ // Compare subnet
8221
+ oldSubnet := old ["subnet" ].([]interface {})
8222
+ newSubnet := new ["subnet" ].([]interface {})
8223
+ if len (oldSubnet ) != len (newSubnet ) {
8224
+ return false
8225
+ }
8226
+ if len (oldSubnet ) > 0 {
8227
+ if ! compareSubnet (oldSubnet [0 ].(map [string ]interface {}), newSubnet [0 ].(map [string ]interface {})) {
8228
+ return false
8229
+ }
8230
+ }
8231
+
8232
+ return true
8233
+ }
8234
+
8235
+ // comparePrimaryIP compares primary IP configurations
8236
+ func comparePrimaryIP (old , new map [string ]interface {}) bool {
8237
+ return old ["id" ] == new ["id" ] &&
8238
+ old ["address" ] == new ["address" ] &&
8239
+ old ["auto_delete" ] == new ["auto_delete" ] &&
8240
+ old ["name" ] == new ["name" ]
8241
+ }
8242
+
8243
+ // compareSubnet compares subnet configurations
8244
+ func compareSubnet (old , new map [string ]interface {}) bool {
8245
+ return old ["id" ] == new ["id" ]
8246
+ }
8247
+ func handleClusterNetworkAttachmentUpdate (d * schema.ResourceData , instanceC * vpcv1.VpcV1 ) error {
8248
+ if d .HasChange ("cluster_network_attachments" ) && ! d .IsNewResource () {
8249
+ old , new := d .GetChange ("cluster_network_attachments" )
8250
+ oldAttachments := old .([]interface {})
8251
+ newAttachments := new .([]interface {})
8252
+
8253
+ // Track attachments to remove, add, and update
8254
+ toRemove := []string {}
8255
+ toAdd := []map [string ]interface {}{}
8256
+ toUpdate := []map [string ]interface {}{}
8257
+
8258
+ // Build map of old attachments by name for easier lookup
8259
+ oldAttachMap := make (map [string ]map [string ]interface {})
8260
+ for _ , attachment := range oldAttachments {
8261
+ attach := attachment .(map [string ]interface {})
8262
+ oldAttachMap [attach ["name" ].(string )] = attach
8263
+ }
8264
+
8265
+ // Analyze new attachments
8266
+ for _ , attachment := range newAttachments {
8267
+ attach := attachment .(map [string ]interface {})
8268
+ name := attach ["name" ].(string )
8269
+
8270
+ if oldAttach , exists := oldAttachMap [name ]; exists {
8271
+ // Check if update needed
8272
+ if ! compareInterfaces (
8273
+ oldAttach ["cluster_network_interface" ].([]interface {})[0 ].(map [string ]interface {}),
8274
+ attach ["cluster_network_interface" ].([]interface {})[0 ].(map [string ]interface {}),
8275
+ ) {
8276
+ toUpdate = append (toUpdate , attach )
8277
+ }
8278
+ delete (oldAttachMap , name )
8279
+ } else {
8280
+ toAdd = append (toAdd , attach )
8281
+ }
8282
+ }
8283
+
8284
+ // Remaining old attachments need to be removed
8285
+ for _ , attach := range oldAttachMap {
8286
+ if id , ok := attach ["id" ].(string ); ok {
8287
+ toRemove = append (toRemove , id )
8288
+ }
8289
+ }
8290
+
8291
+ // Process removals
8292
+ instanceID := d .Id ()
8293
+ for _ , id := range toRemove {
8294
+ deleteOptions := & vpcv1.DeleteInstanceClusterNetworkAttachmentOptions {
8295
+ InstanceID : & instanceID ,
8296
+ ID : & id ,
8297
+ }
8298
+ _ , _ , err := instanceC .DeleteInstanceClusterNetworkAttachment (deleteOptions )
8299
+ if err != nil {
8300
+ return fmt .Errorf ("error removing cluster network attachment: %v" , err )
8301
+ }
8302
+ }
8303
+
8304
+ // Process additions
8305
+ for _ , attach := range toAdd {
8306
+ createOptions := buildCreateClusterNetworkAttachmentOptions (d .Id (), attach )
8307
+ _ , _ , err := instanceC .CreateClusterNetworkAttachment (createOptions )
8308
+ if err != nil {
8309
+ return fmt .Errorf ("error adding cluster network attachment: %v" , err )
8310
+ }
8311
+ }
8312
+
8313
+ // Process updates
8314
+ for _ , attach := range toUpdate {
8315
+ updateOptions := buildUpdateClusterNetworkAttachmentOptions (d .Id (), attach )
8316
+ _ , _ , err := instanceC .UpdateInstanceClusterNetworkAttachment (updateOptions )
8317
+ if err != nil {
8318
+ return fmt .Errorf ("error updating cluster network attachment: %v" , err )
8319
+ }
8320
+ }
8321
+ }
8322
+ return nil
8323
+ }
8324
+
8325
+ func buildCreateClusterNetworkAttachmentOptions (instanceID string , attachment map [string ]interface {}) * vpcv1.CreateClusterNetworkAttachmentOptions {
8326
+ // Extract network interface data
8327
+ networkInterface := attachment ["cluster_network_interface" ].([]interface {})[0 ].(map [string ]interface {})
8328
+
8329
+ // Build cluster network interface
8330
+ clusterNetworkInterface := & vpcv1.InstanceClusterNetworkAttachmentPrototypeClusterNetworkInterface {}
8331
+
8332
+ if autoDelete , ok := networkInterface ["auto_delete" ].(bool ); ok {
8333
+ clusterNetworkInterface .AutoDelete = & autoDelete
8334
+ }
8335
+
8336
+ if name , ok := networkInterface ["name" ].(string ); ok {
8337
+ clusterNetworkInterface .Name = & name
8338
+ }
8339
+
8340
+ // Handle primary IP if present
8341
+ if primaryIPList , ok := networkInterface ["primary_ip" ].([]interface {}); ok && len (primaryIPList ) > 0 {
8342
+ primaryIP := primaryIPList [0 ].(map [string ]interface {})
8343
+ primaryIPPrototype := & vpcv1.ClusterNetworkInterfacePrimaryIPPrototype {}
8344
+
8345
+ if address , ok := primaryIP ["address" ].(string ); ok {
8346
+ primaryIPPrototype .Address = & address
8347
+ }
8348
+ if autoDelete , ok := primaryIP ["auto_delete" ].(bool ); ok {
8349
+ primaryIPPrototype .AutoDelete = & autoDelete
8350
+ }
8351
+ if name , ok := primaryIP ["name" ].(string ); ok {
8352
+ primaryIPPrototype .Name = & name
8353
+ }
8354
+
8355
+ clusterNetworkInterface .PrimaryIP = primaryIPPrototype
8356
+ }
8357
+
8358
+ // Handle subnet if present
8359
+ if subnetList , ok := networkInterface ["subnet" ].([]interface {}); ok && len (subnetList ) > 0 {
8360
+ subnet := subnetList [0 ].(map [string ]interface {})
8361
+ if id , ok := subnet ["id" ].(string ); ok {
8362
+ clusterNetworkInterface .Subnet = & vpcv1.ClusterNetworkSubnetIdentity {
8363
+ ID : & id ,
8364
+ }
8365
+ }
8366
+ }
8367
+
8368
+ // Get attachment name
8369
+ attachmentName := attachment ["name" ].(string )
8370
+
8371
+ // Create the options struct
8372
+ createOptions := & vpcv1.CreateClusterNetworkAttachmentOptions {
8373
+ InstanceID : & instanceID ,
8374
+ Name : & attachmentName ,
8375
+ ClusterNetworkInterface : clusterNetworkInterface ,
8376
+ }
8377
+
8378
+ return createOptions
8379
+ }
8380
+
8381
+ func buildUpdateClusterNetworkAttachmentOptions (instanceID string , attachment map [string ]interface {}) * vpcv1.UpdateInstanceClusterNetworkAttachmentOptions {
8382
+ // Extract network interface data
8383
+ networkInterface := attachment ["cluster_network_interface" ].([]interface {})[0 ].(map [string ]interface {})
8384
+
8385
+ // Build cluster network interface patch
8386
+
8387
+ clusterNetworkInterface := & vpcv1.InstanceClusterNetworkAttachmentPatch {}
8388
+
8389
+ if name , ok := networkInterface ["name" ].(string ); ok {
8390
+ clusterNetworkInterface .Name = & name
8391
+ }
8392
+ clusterNetworkInterfaceAsPatch , _ := clusterNetworkInterface .AsPatch ()
8393
+
8394
+ // Get attachment ID and name
8395
+ attachmentID := attachment ["id" ].(string )
8396
+
8397
+ // Create the options struct
8398
+ updateOptions := & vpcv1.UpdateInstanceClusterNetworkAttachmentOptions {
8399
+ InstanceID : & instanceID ,
8400
+ ID : & attachmentID ,
8401
+ InstanceClusterNetworkAttachmentPatch : clusterNetworkInterfaceAsPatch ,
8402
+ }
8403
+
8404
+ return updateOptions
8405
+ }
0 commit comments