Skip to content
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
37 changes: 3 additions & 34 deletions builder/vsphere/clone/step_clone.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/packerbuilderdata"
"github.com/vmware/govmomi/vim25/types"
"github.com/vmware/packer-plugin-vsphere/builder/vsphere/common"
"github.com/vmware/packer-plugin-vsphere/builder/vsphere/driver"
)
Expand Down Expand Up @@ -341,39 +340,9 @@ func (s *StepCloneVM) cloneFromTemplate(ctx context.Context, state multistep.Sta
}

// Handle multi-disk placement when using a datastore cluster.
var datastoreRefs []*types.ManagedObjectReference
if s.Location.DatastoreCluster != "" && len(disks) > 1 {
if dsSelector, ok := d.(driver.DatastoreSelector); ok {
// Request Storage DRS recommendations for all disks at once for optimal placement.
ui.Sayf("Requesting Storage DRS recommendations for %d disks...", len(disks))

diskDatastores, method, err := dsSelector.SelectDatastoresForDisks(s.Location.DatastoreCluster, disks)
if err != nil {
ui.Errorf("Warning: Failed to get Storage DRS recommendations: %s. Using primary datastore.", err)
if primaryDatastore != nil {
for i := 0; i < len(disks); i++ {
ref := primaryDatastore.Reference()
datastoreRefs = append(datastoreRefs, &ref)
}
}
} else {
// Use the first disk's datastore as the primary datastore.
if len(diskDatastores) > 0 {
datastoreName = diskDatastores[0].Name()
}

for i, ds := range diskDatastores {
ref := ds.Reference()
if method == driver.SelectionMethodDRS {
log.Printf("[INFO] Disk %d: Storage DRS selected datastore '%s'", i+1, ds.Name())
} else {
log.Printf("[INFO] Disk %d: Using first available datastore '%s'", i+1, ds.Name())
}
datastoreRefs = append(datastoreRefs, &ref)
}
}
}
}
datastoreName, datastoreRefs := common.ResolveMultiDiskDatastoreRefs(
ui, d, s.Location.DatastoreCluster, disks, primaryDatastore, datastoreName,
)

vm, err := template.Clone(ctx, &driver.CloneConfig{
Name: s.Location.VMName,
Expand Down
57 changes: 57 additions & 0 deletions builder/vsphere/common/step_resolve_datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"log"

"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/vmware/govmomi/vim25/types"
"github.com/vmware/packer-plugin-vsphere/builder/vsphere/driver"
)

Expand Down Expand Up @@ -89,3 +91,58 @@ func (s *StepResolveDatastore) Run(_ context.Context, state multistep.StateBag)

// Cleanup performs any necessary cleanup.
func (s *StepResolveDatastore) Cleanup(state multistep.StateBag) {}

// ResolveMultiDiskDatastoreRefs requests per-disk Storage DRS placement when a
// datastore cluster is configured with multiple disks. It is the companion to
// StepResolveDatastore for VM create/clone steps that attach more than one disk.
func ResolveMultiDiskDatastoreRefs(
ui packersdk.Ui,
d driver.Driver,
datastoreCluster string,
disks []driver.Disk,
primaryDatastore driver.Datastore,
datastoreName string,
) (string, []*types.ManagedObjectReference) {
if datastoreCluster == "" || len(disks) <= 1 {
return datastoreName, nil
}

dsSelector, ok := d.(driver.DatastoreSelector)
if !ok {
return datastoreName, nil
}

ui.Sayf("Requesting Storage DRS recommendations for %d disks...", len(disks))

diskDatastores, method, err := dsSelector.SelectDatastoresForDisks(datastoreCluster, disks)
if err != nil {
ui.Errorf("Warning: Failed to get Storage DRS recommendations: %s. Using primary datastore.", err)
if primaryDatastore == nil {
return datastoreName, nil
}

datastoreRefs := make([]*types.ManagedObjectReference, 0, len(disks))
for i := 0; i < len(disks); i++ {
ref := primaryDatastore.Reference()
datastoreRefs = append(datastoreRefs, &ref)
}
return datastoreName, datastoreRefs
}

if len(diskDatastores) > 0 {
datastoreName = diskDatastores[0].Name()
}

datastoreRefs := make([]*types.ManagedObjectReference, 0, len(diskDatastores))
for i, ds := range diskDatastores {
ref := ds.Reference()
if method == driver.SelectionMethodDRS {
log.Printf("[INFO] Disk %d: Storage DRS selected datastore '%s'", i+1, ds.Name())
} else {
log.Printf("[INFO] Disk %d: Using first available datastore '%s'", i+1, ds.Name())
}
datastoreRefs = append(datastoreRefs, &ref)
}

return datastoreName, datastoreRefs
}
38 changes: 3 additions & 35 deletions builder/vsphere/iso/step_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,12 @@ package iso
import (
"context"
"fmt"
"log"
"path"
"strings"

"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/packerbuilderdata"
"github.com/vmware/govmomi/vim25/types"
"github.com/vmware/packer-plugin-vsphere/builder/vsphere/common"
"github.com/vmware/packer-plugin-vsphere/builder/vsphere/driver"
)
Expand Down Expand Up @@ -226,39 +224,9 @@ func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multiste
}

// Handle multi-disk placement when using a datastore cluster.
var datastoreRefs []*types.ManagedObjectReference
if s.Location.DatastoreCluster != "" && len(disks) > 1 {
if dsSelector, ok := d.(driver.DatastoreSelector); ok {
// Request Storage DRS recommendations for all disks at once for optimal placement.
ui.Sayf("Requesting Storage DRS recommendations for %d disks...", len(disks))

diskDatastores, method, err := dsSelector.SelectDatastoresForDisks(s.Location.DatastoreCluster, disks)
if err != nil {
ui.Errorf("Warning: Failed to get Storage DRS recommendations: %s. Using primary datastore.", err)
if primaryDatastore != nil {
for i := 0; i < len(disks); i++ {
ref := primaryDatastore.Reference()
datastoreRefs = append(datastoreRefs, &ref)
}
}
} else {
// Use the first disk's datastore as the primary datastore
if len(diskDatastores) > 0 {
datastoreName = diskDatastores[0].Name()
}

for i, ds := range diskDatastores {
ref := ds.Reference()
if method == driver.SelectionMethodDRS {
log.Printf("[INFO] Disk %d: Storage DRS selected datastore '%s'", i+1, ds.Name())
} else {
log.Printf("[INFO] Disk %d: Using first available datastore '%s'", i+1, ds.Name())
}
datastoreRefs = append(datastoreRefs, &ref)
}
}
}
}
datastoreName, datastoreRefs := common.ResolveMultiDiskDatastoreRefs(
ui, d, s.Location.DatastoreCluster, disks, primaryDatastore, datastoreName,
)

vm, err := d.CreateVM(&driver.CreateConfig{
StorageConfig: driver.StorageConfig{
Expand Down
Loading