Skip to content

Commit 35eb929

Browse files
committed
Added patch operations for cluster network attachments
1 parent a054149 commit 35eb929

File tree

1 file changed

+256
-4
lines changed

1 file changed

+256
-4
lines changed

ibm/service/vpc/resource_ibm_is_instance.go

+256-4
Original file line numberDiff line numberDiff line change
@@ -218,10 +218,11 @@ func ResourceIBMISInstance() *schema.Resource {
218218

219219
// cluster changes
220220
"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.",
225226
Elem: &schema.Resource{
226227
Schema: map[string]*schema.Schema{
227228
"cluster_network_interface": &schema.Schema{
@@ -8151,3 +8152,254 @@ func setVolumePrototypesInState(d *schema.ResourceData, instance *vpcv1.Instance
81518152

81528153
return finalList, nil
81538154
}
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

Comments
 (0)