Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add vm to existing vm group #2260

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# <!-- markdownlint-disable first-line-h1 no-inline-html -->

## 2.9.2 (nNot Released)

BUG FIX:
* `resource/vsphere_compute_cluster_vm_group`: Updates resource to allow for additional virtual
machines to be adding or removed from a VM Group. Must be ran in conjunction with and 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 virtual machines to string slices for diffVmGroup.
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 diffVmGroup to find added and removed virtual machines from virtual machine group.
addedVMs, removedVMs := diffVmGroup(existingVMs, newVMs)

// 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 virtual machines with added virtual machines 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)
}

if len(uniqueVMs) == 0 {
return fmt.Errorf("the resultant set of virtual machines in the vm group cannot be empty")
}

// 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 diffVmGroup(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)
}
5 changes: 5 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,11 @@ 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

~> **NOTE:** To update a existing VM group, you must first import the group with `import` command in
[Importing](#importing) section. When importing a VM group, validate that all virtual machines that
need to be in the group are included in the `virtual_machine_ids`; otherwise, any virtual machines
that are not in `virtual_machine_ids` the included will be removed from the group.

## Attribute Reference

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