Skip to content

Commit

Permalink
Add support for compute resources in folders
Browse files Browse the repository at this point in the history
  • Loading branch information
sneal committed Apr 13, 2023
1 parent 430d76c commit f74064e
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 98 deletions.
2 changes: 1 addition & 1 deletion pkg/vcenter/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ func (c *Client) findVM(ctx context.Context, azName, vmNameOrPath string) (*VM,
return nil, err
}

cluster, err := f.Cluster(ctx, vm)
cluster, err := f.VMClusterName(ctx, vm)
if err != nil {
return nil, err
}
Expand Down
29 changes: 15 additions & 14 deletions pkg/vcenter/finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,26 +83,15 @@ func (f *Finder) ResourcePool(ctx context.Context, fullyQualifiedResourcePoolNam
return resourcePool, nil
}

func (f *Finder) ResourcePoolFromSpecRef(ctx context.Context, spec TargetSpec) (*types.ManagedObjectReference, error) {
rp, err := f.ResourcePoolFromSpec(ctx, spec)
func (f *Finder) ResourcePoolRef(ctx context.Context, fullyQualifiedResourcePoolName string) (*types.ManagedObjectReference, error) {
rp, err := f.ResourcePool(ctx, fullyQualifiedResourcePoolName)
if err != nil {
return nil, err
}
r := rp.Reference()
return &r, nil
}

func (f *Finder) ResourcePoolFromSpec(ctx context.Context, spec TargetSpec) (*object.ResourcePool, error) {
// sanity check
if f.Datacenter != spec.Datacenter {
return nil, fmt.Errorf("mismatched resource pool datacenter, expected %s but got %s",
f.Datacenter, spec.Datacenter)
}

longResourcePoolName := spec.FullyQualifiedResourcePool()
return f.ResourcePool(ctx, longResourcePoolName)
}

func (f *Finder) DatastoreRef(ctx context.Context, datastoreName string) (*types.ManagedObjectReference, error) {
ds, err := f.Datastore(ctx, datastoreName)
if err != nil {
Expand Down Expand Up @@ -173,7 +162,19 @@ func (f *Finder) Disks(ctx context.Context, vm *object.VirtualMachine) ([]Disk,
return disks, nil
}

func (f *Finder) Cluster(ctx context.Context, vm *object.VirtualMachine) (string, error) {
func (f *Finder) Cluster(ctx context.Context, clusterName string) (*object.ClusterComputeResource, error) {
l := log.FromContext(ctx)
l.Debugf("Getting cluster %s", clusterName)

finder, err := f.getUnderlyingFinderOrCreate(ctx)
if err != nil {
return nil, err
}

return finder.ClusterComputeResource(ctx, clusterName)
}

func (f *Finder) VMClusterName(ctx context.Context, vm *object.VirtualMachine) (string, error) {
l := log.FromContext(ctx)
l.Debugf("Getting VM %s cluster", vm.Name())

Expand Down
51 changes: 22 additions & 29 deletions pkg/vcenter/finder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,27 +50,46 @@ func TestVirtualMachine(t *testing.T) {
}

func TestCluster(t *testing.T) {
VPXTest(func(ctx context.Context, client *govmomi.Client) {
finder := vcenter.NewFinder("DC0", client)

t.Run("Find cluster", func(t *testing.T) {
cluster, err := finder.Cluster(ctx, "DC0_C0")
require.NoError(t, err)
require.Equal(t, "DC0_C0", cluster.Name())
require.Equal(t, "/DC0/host/DC0_C0", cluster.InventoryPath)
})

t.Run("Non-existent cluster", func(t *testing.T) {
_, err := finder.Cluster(ctx, "not-a-cluster")
require.Error(t, err)
require.Contains(t, err.Error(), "cluster 'not-a-cluster' not found")
})
})
}

func TestVMClusterName(t *testing.T) {
VPXTest(func(ctx context.Context, client *govmomi.Client) {
finder := vcenter.NewFinder("DC0", client)

t.Run("Find cluster", func(t *testing.T) {
vm0, err := finder.VirtualMachine(ctx, "DC0_C0_RP1_VM0")
require.NoError(t, err)
cluster, err := finder.Cluster(ctx, vm0)
cluster, err := finder.VMClusterName(ctx, vm0)
require.NoError(t, err)
require.Equal(t, "DC0_C0", cluster)

vm1, err := finder.VirtualMachine(ctx, "DC0_C0_RP1_VM1")
require.NoError(t, err)
cluster, err = finder.Cluster(ctx, vm1)
cluster, err = finder.VMClusterName(ctx, vm1)
require.NoError(t, err)
require.Equal(t, "DC0_C0", cluster)
})

t.Run("Non-existent cluster", func(t *testing.T) {
vm0, err := finder.VirtualMachine(ctx, "DC0_H0_VM0")
require.NoError(t, err)
_, err = finder.Cluster(ctx, vm0)
_, err = finder.VMClusterName(ctx, vm0)
require.Error(t, err)
require.Contains(t, err.Error(), "found unsupported compute type ComputeResource")
})
Expand All @@ -87,32 +106,6 @@ func TestResourcePool(t *testing.T) {
require.Equal(t, "DC0_C0_RP1", rp.Name())
})

t.Run("Find RP from spec", func(t *testing.T) {
spec := vcenter.TargetSpec{
ResourcePool: "DC0_C0_RP1",
Datacenter: "DC0",
Cluster: "DC0_C0",
}
rp, err := finder.ResourcePoolFromSpec(ctx, spec)
require.NoError(t, err)
require.Equal(t, "DC0_C0_RP1", rp.Name())

rpRef, err := finder.ResourcePoolFromSpecRef(ctx, spec)
require.NoError(t, err)
require.Equal(t, rp.Reference(), *rpRef)
})

t.Run("Find RP from spec errors with DC mismatch", func(t *testing.T) {
spec := vcenter.TargetSpec{
ResourcePool: "DC0_C0_RP1",
Datacenter: "not-a-dc", //doesn't match finder DC
Cluster: "DC0_C0",
}
_, err := finder.ResourcePoolFromSpec(ctx, spec)
require.Error(t, err)
require.Equal(t, "mismatched resource pool datacenter, expected DC0 but got not-a-dc", err.Error())
})

t.Run("Non-existent RP", func(t *testing.T) {
_, err := finder.ResourcePool(ctx, "does-not-exist-RP")
require.Error(t, err)
Expand Down
22 changes: 18 additions & 4 deletions pkg/vcenter/relocate_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,10 @@ func (rs *RelocateSpec) Build(ctx context.Context) (*types.VirtualMachineRelocat
return nil, fmt.Errorf("must set a target VM spec first before calling build")
}

hostRef := rs.targetHost.Reference()

sourceClient, err := rs.sourceClient.getOrCreateUnderlyingClient(ctx)
if err != nil {
return nil, err
}

destinationClient, err := rs.destinationClient.getOrCreateUnderlyingClient(ctx)
if err != nil {
return nil, err
Expand All @@ -78,11 +75,23 @@ func (rs *RelocateSpec) Build(ctx context.Context) (*types.VirtualMachineRelocat
sourceFinder := NewFinder(rs.srcVM.Datacenter, sourceClient)
destinationFinder := NewFinder(rs.vmTargetSpec.Datacenter, destinationClient)

poolRef, err := destinationFinder.ResourcePoolFromSpecRef(ctx, *rs.vmTargetSpec)
// get the target cluster to build a fully qualified resource pool path
targetCluster, err := destinationFinder.Cluster(ctx, rs.vmTargetSpec.Cluster)
if err != nil {
return nil, err
}

// get the (required) specified or default target resource pool
rpPath := targetCluster.InventoryPath + "/Resources"
if rs.vmTargetSpec.ResourcePool != "" {
rpPath += "/" + rs.vmTargetSpec.ResourcePool
}
poolRef, err := destinationFinder.ResourcePoolRef(ctx, rpPath)
if err != nil {
return nil, err
}

// get the destination folder for the VM
folderRef, err := destinationFinder.FolderRef(ctx, rs.vmTargetSpec.Folder)
if err != nil {
if rs.DryRun {
Expand All @@ -96,6 +105,7 @@ func (rs *RelocateSpec) Build(ctx context.Context) (*types.VirtualMachineRelocat
}
}

// map the VM disks to their datastores
var diskMappings []types.VirtualMachineRelocateSpecDiskLocator
for _, srcDisk := range rs.srcVM.Disks {
targetDiskDatastore, ok := rs.vmTargetSpec.Datastores[srcDisk.Datastore]
Expand Down Expand Up @@ -141,6 +151,10 @@ func (rs *RelocateSpec) Build(ctx context.Context) (*types.VirtualMachineRelocat
devicesToChange = append(devicesToChange, &deviceToChange)
}

// the ESXi host we're targeting
hostRef := rs.targetHost.Reference()

// now that we have all the details, create the migration spec
spec := &types.VirtualMachineRelocateSpec{}
spec.Host = &hostRef
spec.Pool = poolRef
Expand Down
36 changes: 36 additions & 0 deletions pkg/vcenter/relocate_spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,39 @@ func TestBuildRelocateSpec(t *testing.T) {
require.Contains(t, spec.Folder.Value, "group-")
})
}

func TestBuildRelocateSpecNoResourcePool(t *testing.T) {
VPXTest(func(ctx context.Context, client *govmomi.Client) {
c := vcenter.NewFromGovmomiClient(client, "DC0")

finder := vcenter.NewFinder("DC0", client)
hosts, err := finder.HostsInCluster(ctx, "DC0_C0")
require.NoError(t, err)

vm, err := c.FindVMInClusters(ctx, "az1", "DC0_C0_RP1_VM0", []string{"DC0_C0"})
require.NoError(t, err)

// since we only have one vcenter everything maps to the same as the source
ts := &vcenter.TargetSpec{
Name: "DC0_C0_RP1_VM0",
Datacenter: "DC0",
Cluster: "DC0_C0",
Folder: "/DC0/vm",
Networks: map[string]string{
"DC0_DVPG0": "DC0_DVPG0",
},
Datastores: map[string]string{
"LocalDS_0": "LocalDS_0",
},
}

rs := vcenter.NewRelocateSpec(c, c).WithSourceVM(vm).WithTargetSpec(ts).WithTargetHost(hosts[0])
spec, err := rs.Build(ctx)
require.NoError(t, err)
require.NotNil(t, spec)

// default resource pool mapping
require.NotNil(t, spec.Pool)
require.Contains(t, spec.Pool.Value, "resgroup-")
})
}
20 changes: 0 additions & 20 deletions pkg/vcenter/target_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@

package vcenter

import (
"fmt"
"strings"

"github.com/vmware-tanzu/vmotion-migration-tool-for-bosh-deployments/pkg/log"
)

type TargetSpec struct {
Name string
Datacenter string
Expand All @@ -21,16 +14,3 @@ type TargetSpec struct {
Datastores map[string]string
Networks map[string]string
}

// FullyQualifiedResourcePool ensures we avoid "multiple found" errors
func (t TargetSpec) FullyQualifiedResourcePool() string {
rp := t.ResourcePool
if !strings.Contains(rp, "/") {
rp = fmt.Sprintf("/%s/host/%s/Resources", t.Datacenter, t.Cluster)
if t.ResourcePool != "" {
rp = rp + "/" + t.ResourcePool
}
log.WithoutContext().Debugf("Found short resource pool name adjusting to %s", rp)
}
return rp
}
30 changes: 0 additions & 30 deletions pkg/vcenter/target_spec_test.go

This file was deleted.

0 comments on commit f74064e

Please sign in to comment.