diff --git a/builder/virtualbox/common/driver.go b/builder/virtualbox/common/driver.go index bfe8069ac..3cfd1f6b9 100644 --- a/builder/virtualbox/common/driver.go +++ b/builder/virtualbox/common/driver.go @@ -22,6 +22,9 @@ type Driver interface { // Create a SCSI controller. CreateSCSIController(vm string, controller string) error + // Create an NVME controller + CreateNVMeController(vm string, controller string, portcount int) error + // Delete a VM by name Delete(string) error diff --git a/builder/virtualbox/common/driver_4_2.go b/builder/virtualbox/common/driver_4_2.go index 03f119e94..86edd9174 100644 --- a/builder/virtualbox/common/driver_4_2.go +++ b/builder/virtualbox/common/driver_4_2.go @@ -51,6 +51,18 @@ func (d *VBox42Driver) CreateSATAController(vmName string, name string, portcoun return d.VBoxManage(command...) } +func (d *VBox42Driver) CreateNVMeController(vmName string, name string, portcount int) error { + command := []string{ + "storagectl", vmName, + "--name", name, + "--add", "pcie", + "--controller", "NVMe", + "--portcount", strconv.Itoa(portcount), + } + + return d.VBoxManage(command...) +} + func (d *VBox42Driver) CreateSCSIController(vmName string, name string) error { command := []string{ diff --git a/builder/virtualbox/common/driver_mock.go b/builder/virtualbox/common/driver_mock.go index 68d57fa64..6ff9e80b8 100644 --- a/builder/virtualbox/common/driver_mock.go +++ b/builder/virtualbox/common/driver_mock.go @@ -13,6 +13,10 @@ type DriverMock struct { CreateSCSIControllerController string CreateSCSIControllerErr error + CreateNVMeControllerVM string + CreateNVMeControllerController string + CreateNVMeControllerErr error + DeleteCalled bool DeleteName string DeleteErr error @@ -70,6 +74,12 @@ func (d *DriverMock) CreateSCSIController(vm string, controller string) error { return d.CreateSCSIControllerErr } +func (d *DriverMock) CreateNVMeController(vm string, controller string, portcount int) error { + d.CreateNVMeControllerVM = vm + d.CreateNVMeControllerController = vm + return d.CreateNVMeControllerErr +} + func (d *DriverMock) Delete(name string) error { d.DeleteCalled = true d.DeleteName = name diff --git a/builder/virtualbox/iso/builder.go b/builder/virtualbox/iso/builder.go index 5ff62c54e..2f3c52a23 100644 --- a/builder/virtualbox/iso/builder.go +++ b/builder/virtualbox/iso/builder.go @@ -89,13 +89,25 @@ type Config struct { // The type of controller that the primary hard drive is attached to, // defaults to ide. When set to sata, the drive is attached to an AHCI SATA // controller. When set to scsi, the drive is attached to an LsiLogic SCSI - // controller. + // controller. When set to pcie, the drive is attached to an NVMe + // controller. Please note that when you use "pcie", you'll need to have + // Virtualbox 6, install an [extension + // pack](https://www.virtualbox.org/wiki/Downloads#VirtualBox6.0.14OracleVMVirtualBoxExtensionPack) + // and you will need to enable EFI mode for nvme to work, ex: + // "vboxmanage": [ + // [ "modifyvm", "{{.Name}}", "--firmware", "EFI" ], + // ] HardDriveInterface string `mapstructure:"hard_drive_interface" required:"false"` // The number of ports available on any SATA controller created, defaults // to 1. VirtualBox supports up to 30 ports on a maximum of 1 SATA // controller. Increasing this value can be useful if you want to attach // additional drives. SATAPortCount int `mapstructure:"sata_port_count" required:"false"` + // The number of ports available on any NVMe controller created, defaults + // to 1. VirtualBox supports up to 255 ports on a maximum of 1 NVMe + // controller. Increasing this value can be useful if you want to attach + // additional drives. + NVMePortCount int `mapstructure:"nvme_port_count" required:"false"` // Forces some guests (i.e. Windows 7+) to treat disks as SSDs and stops // them from performing disk fragmentation. Also set hard_drive_discard to // true to enable TRIM support. @@ -193,9 +205,12 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { "packer-%s-%d", b.config.PackerBuildName, interpolate.InitTime.Unix()) } - if b.config.HardDriveInterface != "ide" && b.config.HardDriveInterface != "sata" && b.config.HardDriveInterface != "scsi" { + switch b.config.HardDriveInterface { + case "ide", "sata", "scsi", "pcie": + // do nothing + default: errs = packer.MultiErrorAppend( - errs, errors.New("hard_drive_interface can only be ide, sata, or scsi")) + errs, errors.New("hard_drive_interface can only be ide, sata, pcie or scsi")) } if b.config.SATAPortCount == 0 { @@ -207,6 +222,15 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { errs, errors.New("sata_port_count cannot be greater than 30")) } + if b.config.NVMePortCount == 0 { + b.config.NVMePortCount = 1 + } + + if b.config.NVMePortCount > 255 { + errs = packer.MultiErrorAppend( + errs, errors.New("nvme_port_count cannot be greater than 255")) + } + if b.config.ISOInterface != "ide" && b.config.ISOInterface != "sata" { errs = packer.MultiErrorAppend( errs, errors.New("iso_interface can only be ide or sata")) diff --git a/builder/virtualbox/iso/builder.hcl2spec.go b/builder/virtualbox/iso/builder.hcl2spec.go index 2eb36629e..6ab143d08 100644 --- a/builder/virtualbox/iso/builder.hcl2spec.go +++ b/builder/virtualbox/iso/builder.hcl2spec.go @@ -104,6 +104,7 @@ type FlatConfig struct { HardDriveDiscard *bool `mapstructure:"hard_drive_discard" required:"false" cty:"hard_drive_discard"` HardDriveInterface *string `mapstructure:"hard_drive_interface" required:"false" cty:"hard_drive_interface"` SATAPortCount *int `mapstructure:"sata_port_count" required:"false" cty:"sata_port_count"` + NVMePortCount *int `mapstructure:"nvme_port_count" required:"false" cty:"nvme_port_count"` HardDriveNonrotational *bool `mapstructure:"hard_drive_nonrotational" required:"false" cty:"hard_drive_nonrotational"` ISOInterface *string `mapstructure:"iso_interface" required:"false" cty:"iso_interface"` KeepRegistered *bool `mapstructure:"keep_registered" required:"false" cty:"keep_registered"` @@ -215,6 +216,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "hard_drive_discard": &hcldec.AttrSpec{Name: "hard_drive_discard", Type: cty.Bool, Required: false}, "hard_drive_interface": &hcldec.AttrSpec{Name: "hard_drive_interface", Type: cty.String, Required: false}, "sata_port_count": &hcldec.AttrSpec{Name: "sata_port_count", Type: cty.Number, Required: false}, + "nvme_port_count": &hcldec.AttrSpec{Name: "nvme_port_count", Type: cty.Number, Required: false}, "hard_drive_nonrotational": &hcldec.AttrSpec{Name: "hard_drive_nonrotational", Type: cty.Bool, Required: false}, "iso_interface": &hcldec.AttrSpec{Name: "iso_interface", Type: cty.String, Required: false}, "keep_registered": &hcldec.AttrSpec{Name: "keep_registered", Type: cty.Bool, Required: false}, diff --git a/builder/virtualbox/iso/step_create_disk.go b/builder/virtualbox/iso/step_create_disk.go index 6a00ea4fa..1a8a80ad6 100644 --- a/builder/virtualbox/iso/step_create_disk.go +++ b/builder/virtualbox/iso/step_create_disk.go @@ -73,6 +73,13 @@ func (s *stepCreateDisk) Run(ctx context.Context, state multistep.StateBag) mult ui.Error(err.Error()) return multistep.ActionHalt } + } else if config.HardDriveInterface == "pcie" { + if err := driver.CreateNVMeController(vmName, "NVMe Controller", config.NVMePortCount); err != nil { + err := fmt.Errorf("Error creating NVMe controller: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } } // Attach the disk to the controller @@ -85,6 +92,10 @@ func (s *stepCreateDisk) Run(ctx context.Context, state multistep.StateBag) mult controllerName = "SCSI Controller" } + if config.HardDriveInterface == "pcie" { + controllerName = "NVMe Controller" + } + nonrotational := "off" if config.HardDriveNonrotational { nonrotational = "on" diff --git a/website/source/partials/builder/virtualbox/iso/_Config-not-required.html.md b/website/source/partials/builder/virtualbox/iso/_Config-not-required.html.md index 951f63183..c636ed567 100644 --- a/website/source/partials/builder/virtualbox/iso/_Config-not-required.html.md +++ b/website/source/partials/builder/virtualbox/iso/_Config-not-required.html.md @@ -47,13 +47,25 @@ - `hard_drive_interface` (string) - The type of controller that the primary hard drive is attached to, defaults to ide. When set to sata, the drive is attached to an AHCI SATA controller. When set to scsi, the drive is attached to an LsiLogic SCSI - controller. + controller. When set to pcie, the drive is attached to an NVMe + controller. Please note that when you use "pcie", you'll need to have + Virtualbox 6, install an [extension + pack](https://www.virtualbox.org/wiki/Downloads#VirtualBox6.0.14OracleVMVirtualBoxExtensionPack) + and you will need to enable EFI mode for nvme to work, ex: + "vboxmanage": [ + [ "modifyvm", "{{.Name}}", "--firmware", "EFI" ], + ] - `sata_port_count` (int) - The number of ports available on any SATA controller created, defaults to 1. VirtualBox supports up to 30 ports on a maximum of 1 SATA controller. Increasing this value can be useful if you want to attach additional drives. +- `nvme_port_count` (int) - The number of ports available on any NVMe controller created, defaults + to 1. VirtualBox supports up to 255 ports on a maximum of 1 NVMe + controller. Increasing this value can be useful if you want to attach + additional drives. + - `hard_drive_nonrotational` (bool) - Forces some guests (i.e. Windows 7+) to treat disks as SSDs and stops them from performing disk fragmentation. Also set hard_drive_discard to true to enable TRIM support.