diff --git a/builder/vsphere/driver/vm.go b/builder/vsphere/driver/vm.go index cb8c3fd64..ed725a9e8 100644 --- a/builder/vsphere/driver/vm.go +++ b/builder/vsphere/driver/vm.go @@ -63,7 +63,7 @@ type NIC struct { } type CreateConfig struct { - DiskControllerType string // example: "scsi", "pvscsi" + DiskControllerType []string // example: "scsi", "pvscsi", "lsilogic" Annotation string Name string @@ -84,6 +84,7 @@ type Disk struct { DiskSize int64 DiskEagerlyScrub bool DiskThinProvisioned bool + ControllerIndex int } func (d *Driver) NewVM(ref *types.ManagedObjectReference) *VirtualMachine { @@ -741,14 +742,22 @@ func addDisk(_ *Driver, devices object.VirtualDeviceList, config *CreateConfig) return nil, errors.New("no storage devices have been defined") } - device, err := devices.CreateSCSIController(config.DiskControllerType) - if err != nil { - return nil, err + if len(config.DiskControllerType) == 0 { + return nil, errors.New("no controllers have been defined") } - devices = append(devices, device) - controller, err := devices.FindDiskController(devices.Name(device)) - if err != nil { - return nil, err + + var controllers []types.BaseVirtualController + for _, controllerType := range config.DiskControllerType { + 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 { @@ -764,7 +773,7 @@ func addDisk(_ *Driver, devices object.VirtualDeviceList, config *CreateConfig) CapacityInKB: dc.DiskSize * 1024, } - devices.AssignController(disk, controller) + devices.AssignController(disk, controllers[dc.ControllerIndex]) devices = append(devices, disk) } diff --git a/builder/vsphere/iso/config.hcl2spec.go b/builder/vsphere/iso/config.hcl2spec.go index a4c20d26b..5f222a83d 100644 --- a/builder/vsphere/iso/config.hcl2spec.go +++ b/builder/vsphere/iso/config.hcl2spec.go @@ -29,7 +29,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"` Firmware *string `mapstructure:"firmware" cty:"firmware" hcl:"firmware"` - DiskControllerType *string `mapstructure:"disk_controller_type" cty:"disk_controller_type" hcl:"disk_controller_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 *bool `mapstructure:"usb_controller" cty:"usb_controller" hcl:"usb_controller"` @@ -160,7 +160,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}, "firmware": &hcldec.AttrSpec{Name: "firmware", Type: cty.String, Required: false}, - "disk_controller_type": &hcldec.AttrSpec{Name: "disk_controller_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())}, "network_adapters": &hcldec.BlockListSpec{TypeName: "network_adapters", Nested: hcldec.ObjectSpec((*FlatNIC)(nil).HCL2Spec())}, "usb_controller": &hcldec.AttrSpec{Name: "usb_controller", Type: cty.Bool, Required: false}, diff --git a/builder/vsphere/iso/step_create.go b/builder/vsphere/iso/step_create.go index fdcce3c8e..09c023afc 100644 --- a/builder/vsphere/iso/step_create.go +++ b/builder/vsphere/iso/step_create.go @@ -49,7 +49,7 @@ type NIC struct { // ```json // "storage": [ // { -// "disk_size": 15000, +// "disk_size": 15000 // }, // { // "disk_size": 20000, @@ -57,6 +57,29 @@ type NIC struct { // } // ], // ``` +// +// Example that creates 2 pvscsi controllers and adds 2 disks to each one: +// ```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 +// } +// ], +// ``` type DiskConfig struct { // The size of the disk in MB. DiskSize int64 `mapstructure:"disk_size" required:"true"` @@ -64,6 +87,8 @@ type DiskConfig struct { 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 { @@ -78,8 +103,8 @@ type CreateConfig struct { GuestOSType string `mapstructure:"guest_os_type"` // Set the Firmware at machine creation. Supported values: `bios`, `efi` or `efi-secure`. Defaults to `bios`. Firmware string `mapstructure:"firmware"` - // Set VM disk controller type. Example `pvscsi`. - DiskControllerType string `mapstructure:"disk_controller_type"` + // Set VM disk controller type. Example `lsilogic`, pvscsi`, or `scsi`. Use a list to define additional controllers. Defaults to `lsilogic` + DiskControllerType []string `mapstructure:"disk_controller_type"` // A collection of one or more disks to be provisioned along with the VM. Storage []DiskConfig `mapstructure:"storage"` // Network adapters @@ -93,11 +118,19 @@ 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.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)) + } } } @@ -149,6 +182,7 @@ func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multiste DiskSize: disk.DiskSize, DiskEagerlyScrub: disk.DiskEagerlyScrub, DiskThinProvisioned: disk.DiskThinProvisioned, + ControllerIndex: disk.DiskControllerIndex, }) } diff --git a/builder/vsphere/iso/step_create.hcl2spec.go b/builder/vsphere/iso/step_create.hcl2spec.go index 644ceedbc..dddacc0d6 100644 --- a/builder/vsphere/iso/step_create.hcl2spec.go +++ b/builder/vsphere/iso/step_create.hcl2spec.go @@ -12,7 +12,7 @@ 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"` Firmware *string `mapstructure:"firmware" cty:"firmware" hcl:"firmware"` - DiskControllerType *string `mapstructure:"disk_controller_type" cty:"disk_controller_type" hcl:"disk_controller_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 *bool `mapstructure:"usb_controller" cty:"usb_controller" hcl:"usb_controller"` @@ -34,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}, "firmware": &hcldec.AttrSpec{Name: "firmware", Type: cty.String, Required: false}, - "disk_controller_type": &hcldec.AttrSpec{Name: "disk_controller_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())}, "network_adapters": &hcldec.BlockListSpec{TypeName: "network_adapters", Nested: hcldec.ObjectSpec((*FlatNIC)(nil).HCL2Spec())}, "usb_controller": &hcldec.AttrSpec{Name: "usb_controller", Type: cty.Bool, Required: false}, @@ -49,6 +49,7 @@ 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. @@ -66,6 +67,7 @@ func (*FlatDiskConfig) HCL2Spec() 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 } diff --git a/website/pages/partials/builder/vsphere/iso/CreateConfig-not-required.mdx b/website/pages/partials/builder/vsphere/iso/CreateConfig-not-required.mdx index 221550f34..0eb894961 100644 --- a/website/pages/partials/builder/vsphere/iso/CreateConfig-not-required.mdx +++ b/website/pages/partials/builder/vsphere/iso/CreateConfig-not-required.mdx @@ -11,7 +11,7 @@ - `firmware` (string) - Set the Firmware at machine creation. Supported values: `bios`, `efi` or `efi-secure`. Defaults to `bios`. -- `disk_controller_type` (string) - Set VM disk controller type. Example `pvscsi`. +- `disk_controller_type` ([]string) - Set VM disk controller type. Example `lsilogic`, pvscsi`, or `scsi`. Use a list to define additional controllers. Defaults to `lsilogic` - `storage` ([]DiskConfig) - A collection of one or more disks to be provisioned along with the VM. diff --git a/website/pages/partials/builder/vsphere/iso/DiskConfig-not-required.mdx b/website/pages/partials/builder/vsphere/iso/DiskConfig-not-required.mdx index 15ca7cc1f..b3d47dc6f 100644 --- a/website/pages/partials/builder/vsphere/iso/DiskConfig-not-required.mdx +++ b/website/pages/partials/builder/vsphere/iso/DiskConfig-not-required.mdx @@ -3,4 +3,6 @@ - `disk_thin_provisioned` (bool) - Enable VMDK thin provisioning for VM. Defaults to `false`. - `disk_eagerly_scrub` (bool) - Enable VMDK eager scrubbing for VM. Defaults to `false`. + +- `disk_controller_index` (int) - The assigned disk controller. Defaults to the first one (0) \ No newline at end of file diff --git a/website/pages/partials/builder/vsphere/iso/DiskConfig.mdx b/website/pages/partials/builder/vsphere/iso/DiskConfig.mdx index 292a182dc..6e9299ac6 100644 --- a/website/pages/partials/builder/vsphere/iso/DiskConfig.mdx +++ b/website/pages/partials/builder/vsphere/iso/DiskConfig.mdx @@ -6,7 +6,7 @@ Example that will create a 15GB and a 20GB disk on the VM. The second disk will ```json "storage": [ { - "disk_size": 15000, + "disk_size": 15000 }, { "disk_size": 20000, @@ -14,3 +14,26 @@ Example that will create a 15GB and a 20GB disk on the VM. The second disk will } ], ``` + +Example that creates 2 pvscsi controllers and adds 2 disks to each one: +```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 + } + ], +```