Skip to content

Commit

Permalink
fix: r/vsphere_compute_cluster_vm_group add vm to exist group
Browse files Browse the repository at this point in the history
I have added code to allow for existing groups to be updated with new vm's, this new code needs cluster import to be ran first on vm group.

#1878

Signed-off-by: Jared Burns <[email protected]>
  • Loading branch information
burnsjared0415 committed Sep 16, 2024
1 parent 46c4ce8 commit d9e15d2
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 2 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# <!-- markdownlint-disable first-line-h1 no-inline-html -->

## 2.9.2 (not Released)

BUG FIX:

* `resource/vsphere_compute_cluster_vm_group.go`: Add new code to handle updating existing VM groups. This will need put ran in conjunction with Import.
([#2260]https://github.com/hashicorp/terraform-provider-vsphere/pull/2260)


## 2.9.1 (September 9, 2024)

BUG FIX:
Expand Down
119 changes: 117 additions & 2 deletions vsphere/resource_vsphere_compute_cluster_vm_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package vsphere

import (
"context"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -63,6 +64,17 @@ func resourceVSphereComputeClusterVMGroupCreate(d *schema.ResourceData, meta int
return err
}

// Check if the VM group already exists
exists, err := resourceVSphereComputeClusterVMGroupFindEntry(cluster, name)
if err != nil {
return err
}

if exists != nil {
log.Printf("[DEBUG] %s: VM group already exists, calling update", exists.Name)
return resourceVSphereComputeClusterVMGroupUpdate(d, meta)
}

info, err := expandClusterVMGroup(d, meta, name)
if err != nil {
return err
Expand Down Expand Up @@ -140,17 +152,82 @@ func resourceVSphereComputeClusterVMGroupUpdate(d *schema.ResourceData, meta int
return err
}

info, err := expandClusterVMGroup(d, meta, name)
// Retrieve the existing VM group information
existingGroup, err := getCurrentVMsInGroup(cluster, name)
if err != nil {
return err
}

// Check if existingGroup is nil
if existingGroup == nil {
return fmt.Errorf("VM group %s not found", name)
}

// Expand the new VM group information
newInfo, err := expandClusterVMGroup(d, meta, name)
if err != nil {
return err
}

// Convert existing and new VMs to string slices for diffVMs
existingVMs := make([]string, len(existingGroup.Vm))
for i, vm := range existingGroup.Vm {
existingVMs[i] = vm.Value
}

newVMs := make([]string, len(newInfo.Vm))
for i, vm := range newInfo.Vm {
newVMs[i] = vm.Value
}

// Use diffVMs to find added and removed VMs
addedVMs, removedVMs := diffVMs(existingVMs, newVMs)

// Log the added and removed VMs
log.Printf("[DEBUG] Added VMs: %v", addedVMs)
log.Printf("[DEBUG] Removed VMs: %v", removedVMs)

// Convert addedVMs and removedVMs back to ManagedObjectReference slices
addedVMRefs := make([]types.ManagedObjectReference, len(addedVMs))
for i, vm := range addedVMs {
addedVMRefs[i] = types.ManagedObjectReference{
Type: "VirtualMachine",
Value: vm,
}
}

removedVMRefs := make([]types.ManagedObjectReference, len(removedVMs))
for i, vm := range removedVMs {
removedVMRefs[i] = types.ManagedObjectReference{
Type: "VirtualMachine",
Value: vm,
}
}

// Merge existing VMs with added VMs and remove duplicates
mergedVMs := append(existingGroup.Vm, addedVMRefs...)
vmMap := make(map[types.ManagedObjectReference]bool)
for _, vm := range mergedVMs {
vmMap[vm] = true
}
for _, vm := range removedVMRefs {
delete(vmMap, vm)
}
uniqueVMs := make([]types.ManagedObjectReference, 0, len(vmMap))
for vm := range vmMap {
uniqueVMs = append(uniqueVMs, vm)
}

// Update the VM group information with the merged list
newInfo.Vm = uniqueVMs

spec := &types.ClusterConfigSpecEx{
GroupSpec: []types.ClusterGroupSpec{
{
ArrayUpdateSpec: types.ArrayUpdateSpec{
Operation: types.ArrayUpdateOperationEdit,
},
Info: info,
Info: newInfo,
},
},
}
Expand Down Expand Up @@ -397,3 +474,41 @@ func resourceVSphereComputeClusterVMGroupClient(meta interface{}) (*govmomi.Clie
}
return client, nil
}

func diffVMs(oldVMs, newVMs []string) ([]string, []string) {
oldVMMap := make(map[string]bool)
for _, vm := range oldVMs {
oldVMMap[vm] = true
}

var addedVMs, removedVMs []string
for _, vm := range newVMs {
if !oldVMMap[vm] {
addedVMs = append(addedVMs, vm)
}
delete(oldVMMap, vm)
}

for vm := range oldVMMap {
removedVMs = append(removedVMs, vm)
}

return addedVMs, removedVMs
}

// getCurrentVMsInGroup retrieves the current VMs in the specified VM group from the vSphere cluster.
func getCurrentVMsInGroup(cluster *object.ClusterComputeResource, groupName string) (*types.ClusterVmGroup, error) {
ctx := context.TODO()
groups, err := cluster.Configuration(ctx)
if err != nil {
return nil, err
}

for _, group := range groups.Group {
if vmGroup, ok := group.(*types.ClusterVmGroup); ok && vmGroup.Name == groupName {
return vmGroup, nil
}
}

return nil, fmt.Errorf("VM group %s not found", groupName)
}
2 changes: 2 additions & 0 deletions website/docs/r/compute_cluster_vm_group.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ resource. Make sure your names are unique across both resources.

[tf-vsphere-cluster-host-group-resource]: /docs/providers/vsphere/r/compute_cluster_host_group.html

** To update a existing group, first import group with imported command in Import section, also note if you import group validate on apply that all groups that are needed to be in the group are added to `virtual_machine_ids`. If you leave any off the list the Virtual Machines will be removed from the group.**

## Attribute Reference

The only attribute this resource exports is the `id` of the resource, which is
Expand Down

0 comments on commit d9e15d2

Please sign in to comment.