Merge pull request #10287 from hashicorp/implement_9990
Add configuration options to add additional storage to a cloned vm
This commit is contained in:
commit
60e62bbb51
|
@ -37,6 +37,8 @@ type FlatConfig struct {
|
|||
MacAddress *string `mapstructure:"mac_address" cty:"mac_address" hcl:"mac_address"`
|
||||
Notes *string `mapstructure:"notes" cty:"notes" hcl:"notes"`
|
||||
VAppConfig *FlatvAppConfig `mapstructure:"vapp" cty:"vapp" hcl:"vapp"`
|
||||
DiskControllerType []string `mapstructure:"disk_controller_type" cty:"disk_controller_type" hcl:"disk_controller_type"`
|
||||
Storage []common.FlatDiskConfig `mapstructure:"storage" cty:"storage" hcl:"storage"`
|
||||
VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"`
|
||||
Folder *string `mapstructure:"folder" cty:"folder" hcl:"folder"`
|
||||
Cluster *string `mapstructure:"cluster" cty:"cluster" hcl:"cluster"`
|
||||
|
@ -174,6 +176,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"mac_address": &hcldec.AttrSpec{Name: "mac_address", Type: cty.String, Required: false},
|
||||
"notes": &hcldec.AttrSpec{Name: "notes", Type: cty.String, Required: false},
|
||||
"vapp": &hcldec.BlockSpec{TypeName: "vapp", Nested: hcldec.ObjectSpec((*FlatvAppConfig)(nil).HCL2Spec())},
|
||||
"disk_controller_type": &hcldec.AttrSpec{Name: "disk_controller_type", Type: cty.List(cty.String), Required: false},
|
||||
"storage": &hcldec.BlockListSpec{TypeName: "storage", Nested: hcldec.ObjectSpec((*common.FlatDiskConfig)(nil).HCL2Spec())},
|
||||
"vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false},
|
||||
"folder": &hcldec.AttrSpec{Name: "folder", Type: cty.String, Required: false},
|
||||
"cluster": &hcldec.AttrSpec{Name: "cluster", Type: cty.String, Required: false},
|
||||
|
|
|
@ -44,11 +44,13 @@ type CloneConfig struct {
|
|||
// Set the vApp Options to a virtual machine.
|
||||
// See the [vApp Options Configuration](/docs/builders/vmware/vsphere-clone#vapp-options-configuration)
|
||||
// to know the available options and how to use it.
|
||||
VAppConfig vAppConfig `mapstructure:"vapp"`
|
||||
VAppConfig vAppConfig `mapstructure:"vapp"`
|
||||
StorageConfig common.StorageConfig `mapstructure:",squash"`
|
||||
}
|
||||
|
||||
func (c *CloneConfig) Prepare() []error {
|
||||
var errs []error
|
||||
errs = append(errs, c.StorageConfig.Prepare()...)
|
||||
|
||||
if c.Template == "" {
|
||||
errs = append(errs, fmt.Errorf("'template' is required"))
|
||||
|
@ -89,6 +91,16 @@ func (s *StepCloneVM) Run(ctx context.Context, state multistep.StateBag) multist
|
|||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
var disks []driver.Disk
|
||||
for _, disk := range s.Config.StorageConfig.Storage {
|
||||
disks = append(disks, driver.Disk{
|
||||
DiskSize: disk.DiskSize,
|
||||
DiskEagerlyScrub: disk.DiskEagerlyScrub,
|
||||
DiskThinProvisioned: disk.DiskThinProvisioned,
|
||||
ControllerIndex: disk.DiskControllerIndex,
|
||||
})
|
||||
}
|
||||
|
||||
vm, err := template.Clone(ctx, &driver.CloneConfig{
|
||||
Name: s.Location.VMName,
|
||||
Folder: s.Location.Folder,
|
||||
|
@ -101,6 +113,10 @@ func (s *StepCloneVM) Run(ctx context.Context, state multistep.StateBag) multist
|
|||
MacAddress: s.Config.MacAddress,
|
||||
Annotation: s.Config.Notes,
|
||||
VAppProperties: s.Config.VAppConfig.Properties,
|
||||
StorageConfig: driver.StorageConfig{
|
||||
DiskControllerType: s.Config.StorageConfig.DiskControllerType,
|
||||
Storage: disks,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
|
|
|
@ -3,19 +3,22 @@ package clone
|
|||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/hashicorp/packer/builder/vsphere/common"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// FlatCloneConfig is an auto-generated flat version of CloneConfig.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatCloneConfig struct {
|
||||
Template *string `mapstructure:"template" cty:"template" hcl:"template"`
|
||||
DiskSize *int64 `mapstructure:"disk_size" cty:"disk_size" hcl:"disk_size"`
|
||||
LinkedClone *bool `mapstructure:"linked_clone" cty:"linked_clone" hcl:"linked_clone"`
|
||||
Network *string `mapstructure:"network" cty:"network" hcl:"network"`
|
||||
MacAddress *string `mapstructure:"mac_address" cty:"mac_address" hcl:"mac_address"`
|
||||
Notes *string `mapstructure:"notes" cty:"notes" hcl:"notes"`
|
||||
VAppConfig *FlatvAppConfig `mapstructure:"vapp" cty:"vapp" hcl:"vapp"`
|
||||
Template *string `mapstructure:"template" cty:"template" hcl:"template"`
|
||||
DiskSize *int64 `mapstructure:"disk_size" cty:"disk_size" hcl:"disk_size"`
|
||||
LinkedClone *bool `mapstructure:"linked_clone" cty:"linked_clone" hcl:"linked_clone"`
|
||||
Network *string `mapstructure:"network" cty:"network" hcl:"network"`
|
||||
MacAddress *string `mapstructure:"mac_address" cty:"mac_address" hcl:"mac_address"`
|
||||
Notes *string `mapstructure:"notes" cty:"notes" hcl:"notes"`
|
||||
VAppConfig *FlatvAppConfig `mapstructure:"vapp" cty:"vapp" hcl:"vapp"`
|
||||
DiskControllerType []string `mapstructure:"disk_controller_type" cty:"disk_controller_type" hcl:"disk_controller_type"`
|
||||
Storage []common.FlatDiskConfig `mapstructure:"storage" cty:"storage" hcl:"storage"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatCloneConfig.
|
||||
|
@ -30,13 +33,15 @@ func (*CloneConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.S
|
|||
// The decoded values from this spec will then be applied to a FlatCloneConfig.
|
||||
func (*FlatCloneConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
s := map[string]hcldec.Spec{
|
||||
"template": &hcldec.AttrSpec{Name: "template", Type: cty.String, Required: false},
|
||||
"disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, Required: false},
|
||||
"linked_clone": &hcldec.AttrSpec{Name: "linked_clone", Type: cty.Bool, Required: false},
|
||||
"network": &hcldec.AttrSpec{Name: "network", Type: cty.String, Required: false},
|
||||
"mac_address": &hcldec.AttrSpec{Name: "mac_address", Type: cty.String, Required: false},
|
||||
"notes": &hcldec.AttrSpec{Name: "notes", Type: cty.String, Required: false},
|
||||
"vapp": &hcldec.BlockSpec{TypeName: "vapp", Nested: hcldec.ObjectSpec((*FlatvAppConfig)(nil).HCL2Spec())},
|
||||
"template": &hcldec.AttrSpec{Name: "template", Type: cty.String, Required: false},
|
||||
"disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, Required: false},
|
||||
"linked_clone": &hcldec.AttrSpec{Name: "linked_clone", Type: cty.Bool, Required: false},
|
||||
"network": &hcldec.AttrSpec{Name: "network", Type: cty.String, Required: false},
|
||||
"mac_address": &hcldec.AttrSpec{Name: "mac_address", Type: cty.String, Required: false},
|
||||
"notes": &hcldec.AttrSpec{Name: "notes", Type: cty.String, Required: false},
|
||||
"vapp": &hcldec.BlockSpec{TypeName: "vapp", Nested: hcldec.ObjectSpec((*FlatvAppConfig)(nil).HCL2Spec())},
|
||||
"disk_controller_type": &hcldec.AttrSpec{Name: "disk_controller_type", Type: cty.List(cty.String), Required: false},
|
||||
"storage": &hcldec.BlockListSpec{TypeName: "storage", Nested: hcldec.ObjectSpec((*common.FlatDiskConfig)(nil).HCL2Spec())},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type StorageConfig,DiskConfig
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Defines the disk storage for a VM.
|
||||
//
|
||||
// Example that will create a 15GB and a 20GB disk on the VM. The second disk will be thin provisioned:
|
||||
//
|
||||
// In JSON:
|
||||
// ```json
|
||||
// "storage": [
|
||||
// {
|
||||
// "disk_size": 15000
|
||||
// },
|
||||
// {
|
||||
// "disk_size": 20000,
|
||||
// "disk_thin_provisioned": true
|
||||
// }
|
||||
// ],
|
||||
// ```
|
||||
// In HCL2:
|
||||
// ```hcl
|
||||
// storage {
|
||||
// disk_size = 15000
|
||||
// }
|
||||
// storage {
|
||||
// disk_size = 20000
|
||||
// disk_thin_provisioned = true
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Example that creates 2 pvscsi controllers and adds 2 disks to each one:
|
||||
//
|
||||
// In JSON:
|
||||
// ```json
|
||||
// "disk_controller_type": ["pvscsi", "pvscsi"],
|
||||
// "storage": [
|
||||
// {
|
||||
// "disk_size": 15000,
|
||||
// "disk_controller_index": 0
|
||||
// },
|
||||
// {
|
||||
// "disk_size": 15000,
|
||||
// "disk_controller_index": 0
|
||||
// },
|
||||
// {
|
||||
// "disk_size": 15000,
|
||||
// "disk_controller_index": 1
|
||||
// },
|
||||
// {
|
||||
// "disk_size": 15000,
|
||||
// "disk_controller_index": 1
|
||||
// }
|
||||
// ],
|
||||
// ```
|
||||
//
|
||||
// In HCL2:
|
||||
// ```hcl
|
||||
// disk_controller_type = ["pvscsi", "pvscsi"]
|
||||
// storage {
|
||||
// disk_size = 15000,
|
||||
// disk_controller_index = 0
|
||||
// }
|
||||
// storage {
|
||||
// disk_size = 15000
|
||||
// disk_controller_index = 0
|
||||
// }
|
||||
// storage {
|
||||
// disk_size = 15000
|
||||
// disk_controller_index = 1
|
||||
// }
|
||||
// storage {
|
||||
// disk_size = 15000
|
||||
// disk_controller_index = 1
|
||||
// }
|
||||
// ```
|
||||
type DiskConfig struct {
|
||||
// The size of the disk in MB.
|
||||
DiskSize int64 `mapstructure:"disk_size" required:"true"`
|
||||
// Enable VMDK thin provisioning for VM. Defaults to `false`.
|
||||
DiskThinProvisioned bool `mapstructure:"disk_thin_provisioned"`
|
||||
// Enable VMDK eager scrubbing for VM. Defaults to `false`.
|
||||
DiskEagerlyScrub bool `mapstructure:"disk_eagerly_scrub"`
|
||||
// The assigned disk controller. Defaults to the first one (0)
|
||||
DiskControllerIndex int `mapstructure:"disk_controller_index"`
|
||||
}
|
||||
|
||||
type StorageConfig struct {
|
||||
// Set VM disk controller type. Example `lsilogic`, `pvscsi`, `nvme`, or `scsi`. Use a list to define additional controllers.
|
||||
// Defaults to `lsilogic`. See
|
||||
// [SCSI, SATA, and NVMe Storage Controller Conditions, Limitations, and Compatibility](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362.html#GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362)
|
||||
// for additional details.
|
||||
DiskControllerType []string `mapstructure:"disk_controller_type"`
|
||||
// Configures a collection of one or more disks to be provisioned along with the VM. See the [Storage Configuration](#storage-configuration).
|
||||
Storage []DiskConfig `mapstructure:"storage"`
|
||||
}
|
||||
|
||||
func (c *StorageConfig) Prepare() []error {
|
||||
var errs []error
|
||||
|
||||
if len(c.Storage) > 0 {
|
||||
for i, storage := range c.Storage {
|
||||
if storage.DiskSize == 0 {
|
||||
errs = append(errs, fmt.Errorf("storage[%d].'disk_size' is required", i))
|
||||
}
|
||||
if storage.DiskControllerIndex >= len(c.DiskControllerType) {
|
||||
errs = append(errs, fmt.Errorf("storage[%d].'disk_controller_index' references an unknown disk controller", i))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
// Code generated by "mapstructure-to-hcl2 -type StorageConfig,DiskConfig"; DO NOT EDIT.
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// FlatDiskConfig is an auto-generated flat version of DiskConfig.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatDiskConfig struct {
|
||||
DiskSize *int64 `mapstructure:"disk_size" required:"true" cty:"disk_size" hcl:"disk_size"`
|
||||
DiskThinProvisioned *bool `mapstructure:"disk_thin_provisioned" cty:"disk_thin_provisioned" hcl:"disk_thin_provisioned"`
|
||||
DiskEagerlyScrub *bool `mapstructure:"disk_eagerly_scrub" cty:"disk_eagerly_scrub" hcl:"disk_eagerly_scrub"`
|
||||
DiskControllerIndex *int `mapstructure:"disk_controller_index" cty:"disk_controller_index" hcl:"disk_controller_index"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatDiskConfig.
|
||||
// FlatDiskConfig is an auto-generated flat version of DiskConfig.
|
||||
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||
func (*DiskConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||
return new(FlatDiskConfig)
|
||||
}
|
||||
|
||||
// HCL2Spec returns the hcl spec of a DiskConfig.
|
||||
// This spec is used by HCL to read the fields of DiskConfig.
|
||||
// The decoded values from this spec will then be applied to a FlatDiskConfig.
|
||||
func (*FlatDiskConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
s := map[string]hcldec.Spec{
|
||||
"disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, Required: false},
|
||||
"disk_thin_provisioned": &hcldec.AttrSpec{Name: "disk_thin_provisioned", Type: cty.Bool, Required: false},
|
||||
"disk_eagerly_scrub": &hcldec.AttrSpec{Name: "disk_eagerly_scrub", Type: cty.Bool, Required: false},
|
||||
"disk_controller_index": &hcldec.AttrSpec{Name: "disk_controller_index", Type: cty.Number, Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// FlatStorageConfig is an auto-generated flat version of StorageConfig.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatStorageConfig struct {
|
||||
DiskControllerType []string `mapstructure:"disk_controller_type" cty:"disk_controller_type" hcl:"disk_controller_type"`
|
||||
Storage []FlatDiskConfig `mapstructure:"storage" cty:"storage" hcl:"storage"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatStorageConfig.
|
||||
// FlatStorageConfig is an auto-generated flat version of StorageConfig.
|
||||
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||
func (*StorageConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||
return new(FlatStorageConfig)
|
||||
}
|
||||
|
||||
// HCL2Spec returns the hcl spec of a StorageConfig.
|
||||
// This spec is used by HCL to read the fields of StorageConfig.
|
||||
// The decoded values from this spec will then be applied to a FlatStorageConfig.
|
||||
func (*FlatStorageConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
s := map[string]hcldec.Spec{
|
||||
"disk_controller_type": &hcldec.AttrSpec{Name: "disk_controller_type", Type: cty.List(cty.String), Required: false},
|
||||
"storage": &hcldec.BlockListSpec{TypeName: "storage", Nested: hcldec.ObjectSpec((*FlatDiskConfig)(nil).HCL2Spec())},
|
||||
}
|
||||
return s
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package driver
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type Disk struct {
|
||||
DiskSize int64
|
||||
DiskEagerlyScrub bool
|
||||
DiskThinProvisioned bool
|
||||
ControllerIndex int
|
||||
}
|
||||
|
||||
type StorageConfig struct {
|
||||
DiskControllerType []string // example: "scsi", "pvscsi", "nvme", "lsilogic"
|
||||
Storage []Disk
|
||||
}
|
||||
|
||||
func (c *StorageConfig) AddStorageDevices(existingDevices object.VirtualDeviceList) ([]types.BaseVirtualDeviceConfigSpec, error) {
|
||||
newDevices := object.VirtualDeviceList{}
|
||||
|
||||
// Create new controller based on existing devices list and add it to the new devices list
|
||||
// to confirm creation
|
||||
var controllers []types.BaseVirtualController
|
||||
for _, controllerType := range c.DiskControllerType {
|
||||
var device types.BaseVirtualDevice
|
||||
var err error
|
||||
if controllerType == "nvme" {
|
||||
device, err = existingDevices.CreateNVMEController()
|
||||
} else {
|
||||
device, err = existingDevices.CreateSCSIController(controllerType)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
existingDevices = append(existingDevices, device)
|
||||
newDevices = append(newDevices, device)
|
||||
controller, err := existingDevices.FindDiskController(existingDevices.Name(device))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
controllers = append(controllers, controller)
|
||||
}
|
||||
|
||||
for _, dc := range c.Storage {
|
||||
disk := &types.VirtualDisk{
|
||||
VirtualDevice: types.VirtualDevice{
|
||||
Key: existingDevices.NewKey(),
|
||||
Backing: &types.VirtualDiskFlatVer2BackingInfo{
|
||||
DiskMode: string(types.VirtualDiskModePersistent),
|
||||
ThinProvisioned: types.NewBool(dc.DiskThinProvisioned),
|
||||
EagerlyScrub: types.NewBool(dc.DiskEagerlyScrub),
|
||||
},
|
||||
},
|
||||
CapacityInKB: dc.DiskSize * 1024,
|
||||
}
|
||||
|
||||
existingDevices.AssignController(disk, controllers[dc.ControllerIndex])
|
||||
newDevices = append(newDevices, disk)
|
||||
}
|
||||
|
||||
return newDevices.ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd)
|
||||
}
|
||||
|
||||
func findDisk(devices object.VirtualDeviceList) (*types.VirtualDisk, error) {
|
||||
var disks []*types.VirtualDisk
|
||||
for _, device := range devices {
|
||||
switch d := device.(type) {
|
||||
case *types.VirtualDisk:
|
||||
disks = append(disks, d)
|
||||
}
|
||||
}
|
||||
|
||||
switch len(disks) {
|
||||
case 0:
|
||||
return nil, errors.New("VM has no disks")
|
||||
case 1:
|
||||
return disks[0], nil
|
||||
}
|
||||
return nil, errors.New("VM has multiple disks")
|
||||
}
|
|
@ -79,6 +79,7 @@ type CloneConfig struct {
|
|||
MacAddress string
|
||||
Annotation string
|
||||
VAppProperties map[string]string
|
||||
StorageConfig StorageConfig
|
||||
}
|
||||
|
||||
type HardwareConfig struct {
|
||||
|
@ -106,8 +107,6 @@ type NIC struct {
|
|||
}
|
||||
|
||||
type CreateConfig struct {
|
||||
DiskControllerType []string // example: "scsi", "pvscsi", "nvme", "lsilogic"
|
||||
|
||||
Annotation string
|
||||
Name string
|
||||
Folder string
|
||||
|
@ -119,14 +118,7 @@ type CreateConfig struct {
|
|||
NICs []NIC
|
||||
USBController []string
|
||||
Version uint // example: 10
|
||||
Storage []Disk
|
||||
}
|
||||
|
||||
type Disk struct {
|
||||
DiskSize int64
|
||||
DiskEagerlyScrub bool
|
||||
DiskThinProvisioned bool
|
||||
ControllerIndex int
|
||||
StorageConfig StorageConfig
|
||||
}
|
||||
|
||||
func (d *VCenterDriver) NewVM(ref *types.ManagedObjectReference) VirtualMachine {
|
||||
|
@ -207,11 +199,12 @@ func (d *VCenterDriver) CreateVM(config *CreateConfig) (VirtualMachine, error) {
|
|||
}
|
||||
|
||||
devices := object.VirtualDeviceList{}
|
||||
|
||||
devices, err = addDisk(d, devices, config)
|
||||
storageConfigSpec, err := config.StorageConfig.AddStorageDevices(devices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
createSpec.DeviceChange = append(createSpec.DeviceChange, storageConfigSpec...)
|
||||
|
||||
devices, err = addNetwork(d, devices, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -235,10 +228,11 @@ func (d *VCenterDriver) CreateVM(config *CreateConfig) (VirtualMachine, error) {
|
|||
devices = append(devices, usb)
|
||||
}
|
||||
|
||||
createSpec.DeviceChange, err = devices.ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd)
|
||||
devicesConfigSpec, err := devices.ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
createSpec.DeviceChange = append(createSpec.DeviceChange, devicesConfigSpec...)
|
||||
|
||||
createSpec.Files = &types.VirtualMachineFileInfo{
|
||||
VmPathName: fmt.Sprintf("[%s]", datastore.Name()),
|
||||
|
@ -341,6 +335,24 @@ func (vm *VirtualMachineDriver) Clone(ctx context.Context, config *CloneConfig)
|
|||
configSpec.Annotation = config.Annotation
|
||||
}
|
||||
|
||||
devices, err := vm.vm.Device(vm.driver.ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
virtualDisks := devices.SelectByType((*types.VirtualDisk)(nil))
|
||||
virtualControllers := devices.SelectByType((*types.VirtualController)(nil))
|
||||
|
||||
// Use existing devices to avoid overlapping configuration
|
||||
existingDevices := object.VirtualDeviceList{}
|
||||
existingDevices = append(existingDevices, virtualDisks...)
|
||||
existingDevices = append(existingDevices, virtualControllers...)
|
||||
|
||||
storageConfigSpec, err := config.StorageConfig.AddStorageDevices(existingDevices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configSpec.DeviceChange = append(configSpec.DeviceChange, storageConfigSpec...)
|
||||
|
||||
if config.Network != "" {
|
||||
net, err := vm.driver.FindNetwork(config.Network)
|
||||
if err != nil {
|
||||
|
@ -616,24 +628,6 @@ func (vm *VirtualMachineDriver) ResizeDisk(diskSize int64) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func findDisk(devices object.VirtualDeviceList) (*types.VirtualDisk, error) {
|
||||
var disks []*types.VirtualDisk
|
||||
for _, device := range devices {
|
||||
switch d := device.(type) {
|
||||
case *types.VirtualDisk:
|
||||
disks = append(disks, d)
|
||||
}
|
||||
}
|
||||
|
||||
switch len(disks) {
|
||||
case 0:
|
||||
return nil, errors.New("VM has no disks")
|
||||
case 1:
|
||||
return disks[0], nil
|
||||
}
|
||||
return nil, errors.New("VM has multiple disks")
|
||||
}
|
||||
|
||||
func (vm *VirtualMachineDriver) PowerOn() error {
|
||||
task, err := vm.vm.PowerOn(vm.driver.ctx)
|
||||
if err != nil {
|
||||
|
@ -849,55 +843,6 @@ func (vm *VirtualMachineDriver) GetDir() (string, error) {
|
|||
return "", fmt.Errorf("cannot find '%s'", vmxName)
|
||||
}
|
||||
|
||||
func addDisk(_ *VCenterDriver, devices object.VirtualDeviceList, config *CreateConfig) (object.VirtualDeviceList, error) {
|
||||
if len(config.Storage) == 0 {
|
||||
return nil, errors.New("no storage devices have been defined")
|
||||
}
|
||||
|
||||
if len(config.DiskControllerType) == 0 {
|
||||
return nil, errors.New("no controllers have been defined")
|
||||
}
|
||||
|
||||
var controllers []types.BaseVirtualController
|
||||
for _, controllerType := range config.DiskControllerType {
|
||||
var device types.BaseVirtualDevice
|
||||
var err error
|
||||
if controllerType == "nvme" {
|
||||
device, err = devices.CreateNVMEController()
|
||||
} else {
|
||||
device, err = devices.CreateSCSIController(controllerType)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
devices = append(devices, device)
|
||||
controller, err := devices.FindDiskController(devices.Name(device))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
controllers = append(controllers, controller)
|
||||
}
|
||||
|
||||
for _, dc := range config.Storage {
|
||||
disk := &types.VirtualDisk{
|
||||
VirtualDevice: types.VirtualDevice{
|
||||
Key: devices.NewKey(),
|
||||
Backing: &types.VirtualDiskFlatVer2BackingInfo{
|
||||
DiskMode: string(types.VirtualDiskModePersistent),
|
||||
ThinProvisioned: types.NewBool(dc.DiskThinProvisioned),
|
||||
EagerlyScrub: types.NewBool(dc.DiskEagerlyScrub),
|
||||
},
|
||||
},
|
||||
CapacityInKB: dc.DiskSize * 1024,
|
||||
}
|
||||
|
||||
devices.AssignController(disk, controllers[dc.ControllerIndex])
|
||||
devices = append(devices, disk)
|
||||
}
|
||||
|
||||
return devices, nil
|
||||
}
|
||||
|
||||
func addNetwork(d *VCenterDriver, devices object.VirtualDeviceList, config *CreateConfig) (object.VirtualDeviceList, error) {
|
||||
if len(config.NICs) == 0 {
|
||||
return nil, errors.New("no network adapters have been defined")
|
||||
|
|
|
@ -33,7 +33,7 @@ type FlatConfig struct {
|
|||
Version *uint `mapstructure:"vm_version" cty:"vm_version" hcl:"vm_version"`
|
||||
GuestOSType *string `mapstructure:"guest_os_type" cty:"guest_os_type" hcl:"guest_os_type"`
|
||||
DiskControllerType []string `mapstructure:"disk_controller_type" cty:"disk_controller_type" hcl:"disk_controller_type"`
|
||||
Storage []FlatDiskConfig `mapstructure:"storage" cty:"storage" hcl:"storage"`
|
||||
Storage []common.FlatDiskConfig `mapstructure:"storage" cty:"storage" hcl:"storage"`
|
||||
NICs []FlatNIC `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"`
|
||||
USBController []string `mapstructure:"usb_controller" cty:"usb_controller" hcl:"usb_controller"`
|
||||
Notes *string `mapstructure:"notes" cty:"notes" hcl:"notes"`
|
||||
|
@ -174,7 +174,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"vm_version": &hcldec.AttrSpec{Name: "vm_version", Type: cty.Number, Required: false},
|
||||
"guest_os_type": &hcldec.AttrSpec{Name: "guest_os_type", Type: cty.String, Required: false},
|
||||
"disk_controller_type": &hcldec.AttrSpec{Name: "disk_controller_type", Type: cty.List(cty.String), Required: false},
|
||||
"storage": &hcldec.BlockListSpec{TypeName: "storage", Nested: hcldec.ObjectSpec((*FlatDiskConfig)(nil).HCL2Spec())},
|
||||
"storage": &hcldec.BlockListSpec{TypeName: "storage", Nested: hcldec.ObjectSpec((*common.FlatDiskConfig)(nil).HCL2Spec())},
|
||||
"network_adapters": &hcldec.BlockListSpec{TypeName: "network_adapters", Nested: hcldec.ObjectSpec((*FlatNIC)(nil).HCL2Spec())},
|
||||
"usb_controller": &hcldec.AttrSpec{Name: "usb_controller", Type: cty.List(cty.String), Required: false},
|
||||
"notes": &hcldec.AttrSpec{Name: "notes", Type: cty.String, Required: false},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type NIC,CreateConfig,DiskConfig
|
||||
//go:generate mapstructure-to-hcl2 -type NIC,CreateConfig
|
||||
|
||||
package iso
|
||||
|
||||
|
@ -56,89 +56,6 @@ type NIC struct {
|
|||
Passthrough *bool `mapstructure:"passthrough"`
|
||||
}
|
||||
|
||||
// Defines the disk storage for a VM.
|
||||
//
|
||||
// Example that will create a 15GB and a 20GB disk on the VM. The second disk will be thin provisioned:
|
||||
//
|
||||
// In JSON:
|
||||
// ```json
|
||||
// "storage": [
|
||||
// {
|
||||
// "disk_size": 15000
|
||||
// },
|
||||
// {
|
||||
// "disk_size": 20000,
|
||||
// "disk_thin_provisioned": true
|
||||
// }
|
||||
// ],
|
||||
// ```
|
||||
// In HCL2:
|
||||
// ```hcl
|
||||
// storage {
|
||||
// disk_size = 15000
|
||||
// }
|
||||
// storage {
|
||||
// disk_size = 20000
|
||||
// disk_thin_provisioned = true
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Example that creates 2 pvscsi controllers and adds 2 disks to each one:
|
||||
//
|
||||
// In JSON:
|
||||
// ```json
|
||||
// "disk_controller_type": ["pvscsi", "pvscsi"],
|
||||
// "storage": [
|
||||
// {
|
||||
// "disk_size": 15000,
|
||||
// "disk_controller_index": 0
|
||||
// },
|
||||
// {
|
||||
// "disk_size": 15000,
|
||||
// "disk_controller_index": 0
|
||||
// },
|
||||
// {
|
||||
// "disk_size": 15000,
|
||||
// "disk_controller_index": 1
|
||||
// },
|
||||
// {
|
||||
// "disk_size": 15000,
|
||||
// "disk_controller_index": 1
|
||||
// }
|
||||
// ],
|
||||
// ```
|
||||
//
|
||||
// In HCL2:
|
||||
// ```hcl
|
||||
// disk_controller_type = ["pvscsi", "pvscsi"]
|
||||
// storage {
|
||||
// disk_size = 15000,
|
||||
// disk_controller_index = 0
|
||||
// }
|
||||
// storage {
|
||||
// disk_size = 15000
|
||||
// disk_controller_index = 0
|
||||
// }
|
||||
// storage {
|
||||
// disk_size = 15000
|
||||
// disk_controller_index = 1
|
||||
// }
|
||||
// storage {
|
||||
// disk_size = 15000
|
||||
// disk_controller_index = 1
|
||||
// }
|
||||
// ```
|
||||
type DiskConfig struct {
|
||||
// The size of the disk in MB.
|
||||
DiskSize int64 `mapstructure:"disk_size" required:"true"`
|
||||
// Enable VMDK thin provisioning for VM. Defaults to `false`.
|
||||
DiskThinProvisioned bool `mapstructure:"disk_thin_provisioned"`
|
||||
// Enable VMDK eager scrubbing for VM. Defaults to `false`.
|
||||
DiskEagerlyScrub bool `mapstructure:"disk_eagerly_scrub"`
|
||||
// The assigned disk controller. Defaults to the first one (0)
|
||||
DiskControllerIndex int `mapstructure:"disk_controller_index"`
|
||||
}
|
||||
|
||||
type CreateConfig struct {
|
||||
// Set VM hardware version. Defaults to the most current VM hardware
|
||||
// version supported by vCenter. See
|
||||
|
@ -148,14 +65,8 @@ type CreateConfig struct {
|
|||
// Set VM OS type. Defaults to `otherGuest`. See [
|
||||
// here](https://code.vmware.com/apis/358/vsphere/doc/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html)
|
||||
// for a full list of possible values.
|
||||
GuestOSType string `mapstructure:"guest_os_type"`
|
||||
// Set VM disk controller type. Example `lsilogic`, `pvscsi`, `nvme`, or `scsi`. Use a list to define additional controllers.
|
||||
// Defaults to `lsilogic`. See
|
||||
// [SCSI, SATA, and NVMe Storage Controller Conditions, Limitations, and Compatibility](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362.html#GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362)
|
||||
// for additional details.
|
||||
DiskControllerType []string `mapstructure:"disk_controller_type"`
|
||||
// A collection of one or more disks to be provisioned along with the VM.
|
||||
Storage []DiskConfig `mapstructure:"storage"`
|
||||
GuestOSType string `mapstructure:"guest_os_type"`
|
||||
StorageConfig common.StorageConfig `mapstructure:",squash"`
|
||||
// Network adapters
|
||||
NICs []NIC `mapstructure:"network_adapters"`
|
||||
// Create USB controllers for the virtual machine. "usb" for a usb 2.0 controller. "xhci" for a usb 3.0 controller. There can only be at most one of each.
|
||||
|
@ -167,21 +78,15 @@ type CreateConfig struct {
|
|||
func (c *CreateConfig) Prepare() []error {
|
||||
var errs []error
|
||||
|
||||
// there should be at least one
|
||||
if len(c.DiskControllerType) == 0 {
|
||||
c.DiskControllerType = append(c.DiskControllerType, "")
|
||||
if len(c.StorageConfig.DiskControllerType) == 0 {
|
||||
c.StorageConfig.DiskControllerType = append(c.StorageConfig.DiskControllerType, "")
|
||||
}
|
||||
|
||||
if len(c.Storage) > 0 {
|
||||
for i, storage := range c.Storage {
|
||||
if storage.DiskSize == 0 {
|
||||
errs = append(errs, fmt.Errorf("storage[%d].'disk_size' is required", i))
|
||||
}
|
||||
if storage.DiskControllerIndex >= len(c.DiskControllerType) {
|
||||
errs = append(errs, fmt.Errorf("storage[%d].'disk_controller_index' references an unknown disk controller", i))
|
||||
}
|
||||
}
|
||||
// there should be at least one
|
||||
if len(c.StorageConfig.Storage) == 0 {
|
||||
errs = append(errs, fmt.Errorf("no storage devices have been defined"))
|
||||
}
|
||||
errs = append(errs, c.StorageConfig.Prepare()...)
|
||||
|
||||
if c.GuestOSType == "" {
|
||||
c.GuestOSType = "otherGuest"
|
||||
|
@ -243,7 +148,7 @@ func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multiste
|
|||
|
||||
// add disk as the first drive for backwards compatibility if the type is defined
|
||||
var disks []driver.Disk
|
||||
for _, disk := range s.Config.Storage {
|
||||
for _, disk := range s.Config.StorageConfig.Storage {
|
||||
disks = append(disks, driver.Disk{
|
||||
DiskSize: disk.DiskSize,
|
||||
DiskEagerlyScrub: disk.DiskEagerlyScrub,
|
||||
|
@ -253,19 +158,21 @@ func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multiste
|
|||
}
|
||||
|
||||
vm, err := d.CreateVM(&driver.CreateConfig{
|
||||
DiskControllerType: s.Config.DiskControllerType,
|
||||
Storage: disks,
|
||||
Annotation: s.Config.Notes,
|
||||
Name: s.Location.VMName,
|
||||
Folder: s.Location.Folder,
|
||||
Cluster: s.Location.Cluster,
|
||||
Host: s.Location.Host,
|
||||
ResourcePool: s.Location.ResourcePool,
|
||||
Datastore: s.Location.Datastore,
|
||||
GuestOS: s.Config.GuestOSType,
|
||||
NICs: networkCards,
|
||||
USBController: s.Config.USBController,
|
||||
Version: s.Config.Version,
|
||||
StorageConfig: driver.StorageConfig{
|
||||
DiskControllerType: s.Config.StorageConfig.DiskControllerType,
|
||||
Storage: disks,
|
||||
},
|
||||
Annotation: s.Config.Notes,
|
||||
Name: s.Location.VMName,
|
||||
Folder: s.Location.Folder,
|
||||
Cluster: s.Location.Cluster,
|
||||
Host: s.Location.Host,
|
||||
ResourcePool: s.Location.ResourcePool,
|
||||
Datastore: s.Location.Datastore,
|
||||
GuestOS: s.Config.GuestOSType,
|
||||
NICs: networkCards,
|
||||
USBController: s.Config.USBController,
|
||||
Version: s.Config.Version,
|
||||
})
|
||||
if err != nil {
|
||||
state.Put("error", fmt.Errorf("error creating vm: %v", err))
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
// Code generated by "mapstructure-to-hcl2 -type NIC,CreateConfig,DiskConfig"; DO NOT EDIT.
|
||||
// Code generated by "mapstructure-to-hcl2 -type NIC,CreateConfig"; DO NOT EDIT.
|
||||
package iso
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/hashicorp/packer/builder/vsphere/common"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// FlatCreateConfig is an auto-generated flat version of CreateConfig.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatCreateConfig struct {
|
||||
Version *uint `mapstructure:"vm_version" cty:"vm_version" hcl:"vm_version"`
|
||||
GuestOSType *string `mapstructure:"guest_os_type" cty:"guest_os_type" hcl:"guest_os_type"`
|
||||
DiskControllerType []string `mapstructure:"disk_controller_type" cty:"disk_controller_type" hcl:"disk_controller_type"`
|
||||
Storage []FlatDiskConfig `mapstructure:"storage" cty:"storage" hcl:"storage"`
|
||||
NICs []FlatNIC `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"`
|
||||
USBController []string `mapstructure:"usb_controller" cty:"usb_controller" hcl:"usb_controller"`
|
||||
Notes *string `mapstructure:"notes" cty:"notes" hcl:"notes"`
|
||||
Version *uint `mapstructure:"vm_version" cty:"vm_version" hcl:"vm_version"`
|
||||
GuestOSType *string `mapstructure:"guest_os_type" cty:"guest_os_type" hcl:"guest_os_type"`
|
||||
DiskControllerType []string `mapstructure:"disk_controller_type" cty:"disk_controller_type" hcl:"disk_controller_type"`
|
||||
Storage []common.FlatDiskConfig `mapstructure:"storage" cty:"storage" hcl:"storage"`
|
||||
NICs []FlatNIC `mapstructure:"network_adapters" cty:"network_adapters" hcl:"network_adapters"`
|
||||
USBController []string `mapstructure:"usb_controller" cty:"usb_controller" hcl:"usb_controller"`
|
||||
Notes *string `mapstructure:"notes" cty:"notes" hcl:"notes"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatCreateConfig.
|
||||
|
@ -33,7 +34,7 @@ func (*FlatCreateConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"vm_version": &hcldec.AttrSpec{Name: "vm_version", Type: cty.Number, Required: false},
|
||||
"guest_os_type": &hcldec.AttrSpec{Name: "guest_os_type", Type: cty.String, Required: false},
|
||||
"disk_controller_type": &hcldec.AttrSpec{Name: "disk_controller_type", Type: cty.List(cty.String), Required: false},
|
||||
"storage": &hcldec.BlockListSpec{TypeName: "storage", Nested: hcldec.ObjectSpec((*FlatDiskConfig)(nil).HCL2Spec())},
|
||||
"storage": &hcldec.BlockListSpec{TypeName: "storage", Nested: hcldec.ObjectSpec((*common.FlatDiskConfig)(nil).HCL2Spec())},
|
||||
"network_adapters": &hcldec.BlockListSpec{TypeName: "network_adapters", Nested: hcldec.ObjectSpec((*FlatNIC)(nil).HCL2Spec())},
|
||||
"usb_controller": &hcldec.AttrSpec{Name: "usb_controller", Type: cty.List(cty.String), Required: false},
|
||||
"notes": &hcldec.AttrSpec{Name: "notes", Type: cty.String, Required: false},
|
||||
|
@ -41,35 +42,6 @@ func (*FlatCreateConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
return s
|
||||
}
|
||||
|
||||
// FlatDiskConfig is an auto-generated flat version of DiskConfig.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatDiskConfig struct {
|
||||
DiskSize *int64 `mapstructure:"disk_size" required:"true" cty:"disk_size" hcl:"disk_size"`
|
||||
DiskThinProvisioned *bool `mapstructure:"disk_thin_provisioned" cty:"disk_thin_provisioned" hcl:"disk_thin_provisioned"`
|
||||
DiskEagerlyScrub *bool `mapstructure:"disk_eagerly_scrub" cty:"disk_eagerly_scrub" hcl:"disk_eagerly_scrub"`
|
||||
DiskControllerIndex *int `mapstructure:"disk_controller_index" cty:"disk_controller_index" hcl:"disk_controller_index"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatDiskConfig.
|
||||
// FlatDiskConfig is an auto-generated flat version of DiskConfig.
|
||||
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||
func (*DiskConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||
return new(FlatDiskConfig)
|
||||
}
|
||||
|
||||
// HCL2Spec returns the hcl spec of a DiskConfig.
|
||||
// This spec is used by HCL to read the fields of DiskConfig.
|
||||
// The decoded values from this spec will then be applied to a FlatDiskConfig.
|
||||
func (*FlatDiskConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
s := map[string]hcldec.Spec{
|
||||
"disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, Required: false},
|
||||
"disk_thin_provisioned": &hcldec.AttrSpec{Name: "disk_thin_provisioned", Type: cty.Bool, Required: false},
|
||||
"disk_eagerly_scrub": &hcldec.AttrSpec{Name: "disk_eagerly_scrub", Type: cty.Bool, Required: false},
|
||||
"disk_controller_index": &hcldec.AttrSpec{Name: "disk_controller_index", Type: cty.Number, Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// FlatNIC is an auto-generated flat version of NIC.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatNIC struct {
|
||||
|
|
|
@ -17,14 +17,23 @@ import (
|
|||
|
||||
func TestCreateConfig_Prepare(t *testing.T) {
|
||||
// Empty config - check defaults
|
||||
config := &CreateConfig{}
|
||||
config := &CreateConfig{
|
||||
// Storage is required
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if errs := config.Prepare(); len(errs) != 0 {
|
||||
t.Fatalf("Config preprare should not fail")
|
||||
t.Fatalf("Config preprare should not fail: %s", errs[0])
|
||||
}
|
||||
if config.GuestOSType != "otherGuest" {
|
||||
t.Fatalf("GuestOSType should default to 'otherGuest'")
|
||||
}
|
||||
if len(config.DiskControllerType) != 1 {
|
||||
if len(config.StorageConfig.DiskControllerType) != 1 {
|
||||
t.Fatalf("DiskControllerType should have at least one element as default")
|
||||
}
|
||||
|
||||
|
@ -38,10 +47,12 @@ func TestCreateConfig_Prepare(t *testing.T) {
|
|||
{
|
||||
name: "Storage validate disk_size",
|
||||
config: &CreateConfig{
|
||||
Storage: []DiskConfig{
|
||||
{
|
||||
DiskSize: 0,
|
||||
DiskThinProvisioned: true,
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 0,
|
||||
DiskThinProvisioned: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -51,10 +62,12 @@ func TestCreateConfig_Prepare(t *testing.T) {
|
|||
{
|
||||
name: "Storage validate disk_controller_index",
|
||||
config: &CreateConfig{
|
||||
Storage: []DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
DiskControllerIndex: 3,
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
DiskControllerIndex: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -65,6 +78,13 @@ func TestCreateConfig_Prepare(t *testing.T) {
|
|||
name: "USBController validate 'usb' and 'xhci' can be set together",
|
||||
config: &CreateConfig{
|
||||
USBController: []string{"usb", "xhci"},
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: false,
|
||||
},
|
||||
|
@ -72,6 +92,13 @@ func TestCreateConfig_Prepare(t *testing.T) {
|
|||
name: "USBController validate '1' and '0' can be set together",
|
||||
config: &CreateConfig{
|
||||
USBController: []string{"1", "0"},
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: false,
|
||||
},
|
||||
|
@ -79,6 +106,13 @@ func TestCreateConfig_Prepare(t *testing.T) {
|
|||
name: "USBController validate 'true' and 'false' can be set together",
|
||||
config: &CreateConfig{
|
||||
USBController: []string{"true", "false"},
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: false,
|
||||
},
|
||||
|
@ -86,6 +120,13 @@ func TestCreateConfig_Prepare(t *testing.T) {
|
|||
name: "USBController validate 'true' and 'usb' cannot be set together",
|
||||
config: &CreateConfig{
|
||||
USBController: []string{"true", "usb"},
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "there can only be one usb controller and one xhci controller",
|
||||
|
@ -94,6 +135,13 @@ func TestCreateConfig_Prepare(t *testing.T) {
|
|||
name: "USBController validate '1' and 'usb' cannot be set together",
|
||||
config: &CreateConfig{
|
||||
USBController: []string{"1", "usb"},
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "there can only be one usb controller and one xhci controller",
|
||||
|
@ -102,6 +150,13 @@ func TestCreateConfig_Prepare(t *testing.T) {
|
|||
name: "USBController validate 'xhci' cannot be set more that once",
|
||||
config: &CreateConfig{
|
||||
USBController: []string{"xhci", "xhci"},
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "there can only be one usb controller and one xhci controller",
|
||||
|
@ -110,6 +165,13 @@ func TestCreateConfig_Prepare(t *testing.T) {
|
|||
name: "USBController validate unknown value cannot be set",
|
||||
config: &CreateConfig{
|
||||
USBController: []string{"unknown"},
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "usb_controller[0] references an unknown usb controller",
|
||||
|
@ -127,7 +189,7 @@ func TestCreateConfig_Prepare(t *testing.T) {
|
|||
}
|
||||
} else {
|
||||
if len(errs) != 0 {
|
||||
t.Fatalf("Config preprare should not fail")
|
||||
t.Fatalf("Config preprare should not fail: %s", errs[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -294,13 +356,15 @@ func basicLocationConfig() *common.LocationConfig {
|
|||
|
||||
func createConfig() *CreateConfig {
|
||||
return &CreateConfig{
|
||||
Version: 1,
|
||||
GuestOSType: "ubuntu64Guest",
|
||||
DiskControllerType: []string{"pvscsi"},
|
||||
Storage: []DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
DiskThinProvisioned: true,
|
||||
Version: 1,
|
||||
GuestOSType: "ubuntu64Guest",
|
||||
StorageConfig: common.StorageConfig{
|
||||
DiskControllerType: []string{"pvscsi"},
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
DiskThinProvisioned: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
NICs: []NIC{
|
||||
|
@ -324,7 +388,7 @@ func driverCreateConfig(config *CreateConfig, location *common.LocationConfig) *
|
|||
}
|
||||
|
||||
var disks []driver.Disk
|
||||
for _, disk := range config.Storage {
|
||||
for _, disk := range config.StorageConfig.Storage {
|
||||
disks = append(disks, driver.Disk{
|
||||
DiskSize: disk.DiskSize,
|
||||
DiskEagerlyScrub: disk.DiskEagerlyScrub,
|
||||
|
@ -334,18 +398,20 @@ func driverCreateConfig(config *CreateConfig, location *common.LocationConfig) *
|
|||
}
|
||||
|
||||
return &driver.CreateConfig{
|
||||
DiskControllerType: config.DiskControllerType,
|
||||
Storage: disks,
|
||||
Annotation: config.Notes,
|
||||
Name: location.VMName,
|
||||
Folder: location.Folder,
|
||||
Cluster: location.Cluster,
|
||||
Host: location.Host,
|
||||
ResourcePool: location.ResourcePool,
|
||||
Datastore: location.Datastore,
|
||||
GuestOS: config.GuestOSType,
|
||||
NICs: networkCards,
|
||||
USBController: config.USBController,
|
||||
Version: config.Version,
|
||||
StorageConfig: driver.StorageConfig{
|
||||
DiskControllerType: config.StorageConfig.DiskControllerType,
|
||||
Storage: disks,
|
||||
},
|
||||
Annotation: config.Notes,
|
||||
Name: location.VMName,
|
||||
Folder: location.Folder,
|
||||
Cluster: location.Cluster,
|
||||
Host: location.Host,
|
||||
ResourcePool: location.ResourcePool,
|
||||
Datastore: location.Datastore,
|
||||
GuestOS: config.GuestOSType,
|
||||
NICs: networkCards,
|
||||
USBController: config.USBController,
|
||||
Version: config.Version,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,21 @@ necessary for this build to succeed and can be found further down the page.
|
|||
|
||||
@include 'builder/vsphere/clone/CloneConfig-not-required.mdx'
|
||||
|
||||
@include 'builder/vsphere/common/StorageConfig-not-required.mdx'
|
||||
|
||||
### Storage Configuration
|
||||
|
||||
When cloning a VM, the storage configuration can be used to add additional storage and disk controllers. The resulting VM
|
||||
will contain the origin VM storage and disk controller plus the new configured ones.
|
||||
|
||||
@include 'builder/vsphere/common/DiskConfig.mdx'
|
||||
|
||||
@include 'builder/vsphere/common/DiskConfig-required.mdx'
|
||||
|
||||
#### Optional
|
||||
|
||||
@include 'builder/vsphere/common/DiskConfig-not-required.mdx'
|
||||
|
||||
### vApp Options Configuration
|
||||
|
||||
@include 'builder/vsphere/clone/vAppConfig-not-required.mdx'
|
||||
|
|
|
@ -186,6 +186,8 @@ iso_paths = [
|
|||
|
||||
@include 'builder/vsphere/iso/CreateConfig-not-required.mdx'
|
||||
|
||||
@include 'builder/vsphere/common/StorageConfig-not-required.mdx'
|
||||
|
||||
### Network Adapter Configuration
|
||||
|
||||
@include 'builder/vsphere/iso/NIC.mdx'
|
||||
|
@ -198,13 +200,13 @@ iso_paths = [
|
|||
|
||||
### Storage Configuration
|
||||
|
||||
@include 'builder/vsphere/iso/DiskConfig.mdx'
|
||||
@include 'builder/vsphere/common/DiskConfig.mdx'
|
||||
|
||||
@include 'builder/vsphere/iso/DiskConfig-required.mdx'
|
||||
@include 'builder/vsphere/common/DiskConfig-required.mdx'
|
||||
|
||||
#### Optional
|
||||
|
||||
@include 'builder/vsphere/iso/DiskConfig-not-required.mdx'
|
||||
@include 'builder/vsphere/common/DiskConfig-not-required.mdx'
|
||||
|
||||
### Export Configuration
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/iso/step_create.go; DO NOT EDIT MANUALLY -->
|
||||
<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/common/storage_config.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `disk_thin_provisioned` (bool) - Enable VMDK thin provisioning for VM. Defaults to `false`.
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/iso/step_create.go; DO NOT EDIT MANUALLY -->
|
||||
<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/common/storage_config.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `disk_size` (int64) - The size of the disk in MB.
|
|
@ -1,4 +1,4 @@
|
|||
<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/iso/step_create.go; DO NOT EDIT MANUALLY -->
|
||||
<!-- Code generated from the comments of the DiskConfig struct in builder/vsphere/common/storage_config.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
Defines the disk storage for a VM.
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<!-- Code generated from the comments of the StorageConfig struct in builder/vsphere/common/storage_config.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `disk_controller_type` ([]string) - Set VM disk controller type. Example `lsilogic`, `pvscsi`, `nvme`, or `scsi`. Use a list to define additional controllers.
|
||||
Defaults to `lsilogic`. See
|
||||
[SCSI, SATA, and NVMe Storage Controller Conditions, Limitations, and Compatibility](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362.html#GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362)
|
||||
for additional details.
|
||||
|
||||
- `storage` ([]DiskConfig) - Configures a collection of one or more disks to be provisioned along with the VM. See the [Storage Configuration](#storage-configuration).
|
|
@ -9,13 +9,6 @@
|
|||
here](https://code.vmware.com/apis/358/vsphere/doc/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html)
|
||||
for a full list of possible values.
|
||||
|
||||
- `disk_controller_type` ([]string) - Set VM disk controller type. Example `lsilogic`, `pvscsi`, `nvme`, or `scsi`. Use a list to define additional controllers.
|
||||
Defaults to `lsilogic`. See
|
||||
[SCSI, SATA, and NVMe Storage Controller Conditions, Limitations, and Compatibility](https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.vsphere.vm_admin.doc/GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362.html#GUID-5872D173-A076-42FE-8D0B-9DB0EB0E7362)
|
||||
for additional details.
|
||||
|
||||
- `storage` ([]DiskConfig) - A collection of one or more disks to be provisioned along with the VM.
|
||||
|
||||
- `network_adapters` ([]NIC) - Network adapters
|
||||
|
||||
- `usb_controller` ([]string) - Create USB controllers for the virtual machine. "usb" for a usb 2.0 controller. "xhci" for a usb 3.0 controller. There can only be at most one of each.
|
||||
|
|
Loading…
Reference in New Issue