Added VirtualBox ISO builder option to create additional disks (#10674)

This commit is contained in:
Thomas Dreibholz 2021-03-11 16:09:30 +01:00 committed by GitHub
parent 9944031580
commit 1a5678dd86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 92 additions and 54 deletions

View File

@ -8,6 +8,8 @@ import (
"github.com/hashicorp/packer-plugin-sdk/multistep" "github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer" packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"strconv"
) )
// This step attaches the boot ISO, cd_files iso, and guest additions to the // This step attaches the boot ISO, cd_files iso, and guest additions to the
@ -69,49 +71,50 @@ func (s *StepAttachISOs) Run(ctx context.Context, state multistep.StateBag) mult
// We have three different potential isos we can attach, so let's // We have three different potential isos we can attach, so let's
// assign each one its own spot so they don't conflict. // assign each one its own spot so they don't conflict.
var controllerName, device, port string var controllerName string
var device, port int
switch diskCategory { switch diskCategory {
case "boot_iso": case "boot_iso":
// figure out controller path // figure out controller path
controllerName = "IDE Controller" controllerName = "IDE Controller"
port = "0" port = 0
device = "1" device = 1
if s.ISOInterface == "sata" { if s.ISOInterface == "sata" {
controllerName = "SATA Controller" controllerName = "SATA Controller"
port = "1" port = 15
device = "0" device = 0
} else if s.ISOInterface == "virtio" { } else if s.ISOInterface == "virtio" {
controllerName = "VirtIO Controller" controllerName = "VirtIO Controller"
port = "1" port = 15
device = "0" device = 0
} }
ui.Message("Mounting boot ISO...") ui.Message("Mounting boot ISO...")
case "guest_additions": case "guest_additions":
controllerName = "IDE Controller" controllerName = "IDE Controller"
port = "1" port = 1
device = "0" device = 0
if s.GuestAdditionsInterface == "sata" { if s.GuestAdditionsInterface == "sata" {
controllerName = "SATA Controller" controllerName = "SATA Controller"
port = "2" port = 14
device = "0" device = 0
} else if s.GuestAdditionsInterface == "virtio" { } else if s.GuestAdditionsInterface == "virtio" {
controllerName = "VirtIO Controller" controllerName = "VirtIO Controller"
port = "2" port = 14
device = "0" device = 0
} }
ui.Message("Mounting guest additions ISO...") ui.Message("Mounting guest additions ISO...")
case "cd_files": case "cd_files":
controllerName = "IDE Controller" controllerName = "IDE Controller"
port = "1" port = 1
device = "1" device = 1
if s.ISOInterface == "sata" { if s.ISOInterface == "sata" {
controllerName = "SATA Controller" controllerName = "SATA Controller"
port = "3" port = 13
device = "0" device = 0
} else if s.ISOInterface == "virtio" { } else if s.ISOInterface == "virtio" {
controllerName = "VirtIO Controller" controllerName = "VirtIO Controller"
port = "3" port = 13
device = "0" device = 0
} }
ui.Message("Mounting cd_files ISO...") ui.Message("Mounting cd_files ISO...")
} }
@ -120,8 +123,8 @@ func (s *StepAttachISOs) Run(ctx context.Context, state multistep.StateBag) mult
command := []string{ command := []string{
"storageattach", vmName, "storageattach", vmName,
"--storagectl", controllerName, "--storagectl", controllerName,
"--port", port, "--port", strconv.Itoa(port),
"--device", device, "--device", strconv.Itoa(device),
"--type", "dvddrive", "--type", "dvddrive",
"--medium", isoPath, "--medium", isoPath,
} }
@ -137,8 +140,8 @@ func (s *StepAttachISOs) Run(ctx context.Context, state multistep.StateBag) mult
unmountCommand := []string{ unmountCommand := []string{
"storageattach", vmName, "storageattach", vmName,
"--storagectl", controllerName, "--storagectl", controllerName,
"--port", port, "--port", strconv.Itoa(port),
"--device", device, "--device", strconv.Itoa(device),
"--type", "dvddrive", "--type", "dvddrive",
"--medium", "none", "--medium", "none",
} }

View File

@ -149,6 +149,12 @@ type Config struct {
// When set to sata, the drive is attached to an AHCI SATA controller. // When set to sata, the drive is attached to an AHCI SATA controller.
// When set to virtio, the drive is attached to a VirtIO controller. // When set to virtio, the drive is attached to a VirtIO controller.
ISOInterface string `mapstructure:"iso_interface" required:"false"` ISOInterface string `mapstructure:"iso_interface" required:"false"`
// Additional disks to create. Uses `vm_name` as the disk name template and
// appends `-#` where `#` is the position in the array. `#` starts at 1 since 0
// is the default disk. Each value represents the disk image size in MiB.
// Each additional disk uses the same disk parameters as the default disk.
// Unset by default.
AdditionalDiskSize []uint `mapstructure:"disk_additional_size" required:"false"`
// Set this to true if you would like to keep the VM registered with // Set this to true if you would like to keep the VM registered with
// virtualbox. Defaults to false. // virtualbox. Defaults to false.
KeepRegistered bool `mapstructure:"keep_registered" required:"false"` KeepRegistered bool `mapstructure:"keep_registered" required:"false"`

View File

@ -135,6 +135,7 @@ type FlatConfig struct {
NVMePortCount *int `mapstructure:"nvme_port_count" required:"false" cty:"nvme_port_count" hcl:"nvme_port_count"` NVMePortCount *int `mapstructure:"nvme_port_count" required:"false" cty:"nvme_port_count" hcl:"nvme_port_count"`
HardDriveNonrotational *bool `mapstructure:"hard_drive_nonrotational" required:"false" cty:"hard_drive_nonrotational" hcl:"hard_drive_nonrotational"` HardDriveNonrotational *bool `mapstructure:"hard_drive_nonrotational" required:"false" cty:"hard_drive_nonrotational" hcl:"hard_drive_nonrotational"`
ISOInterface *string `mapstructure:"iso_interface" required:"false" cty:"iso_interface" hcl:"iso_interface"` ISOInterface *string `mapstructure:"iso_interface" required:"false" cty:"iso_interface" hcl:"iso_interface"`
AdditionalDiskSize []uint `mapstructure:"disk_additional_size" required:"false" cty:"disk_additional_size" hcl:"disk_additional_size"`
KeepRegistered *bool `mapstructure:"keep_registered" required:"false" cty:"keep_registered" hcl:"keep_registered"` KeepRegistered *bool `mapstructure:"keep_registered" required:"false" cty:"keep_registered" hcl:"keep_registered"`
SkipExport *bool `mapstructure:"skip_export" required:"false" cty:"skip_export" hcl:"skip_export"` SkipExport *bool `mapstructure:"skip_export" required:"false" cty:"skip_export" hcl:"skip_export"`
VMName *string `mapstructure:"vm_name" required:"false" cty:"vm_name" hcl:"vm_name"` VMName *string `mapstructure:"vm_name" required:"false" cty:"vm_name" hcl:"vm_name"`
@ -277,6 +278,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"nvme_port_count": &hcldec.AttrSpec{Name: "nvme_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}, "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}, "iso_interface": &hcldec.AttrSpec{Name: "iso_interface", Type: cty.String, Required: false},
"disk_additional_size": &hcldec.AttrSpec{Name: "disk_additional_size", Type: cty.List(cty.Number), Required: false},
"keep_registered": &hcldec.AttrSpec{Name: "keep_registered", Type: cty.Bool, Required: false}, "keep_registered": &hcldec.AttrSpec{Name: "keep_registered", Type: cty.Bool, Required: false},
"skip_export": &hcldec.AttrSpec{Name: "skip_export", Type: cty.Bool, Required: false}, "skip_export": &hcldec.AttrSpec{Name: "skip_export", Type: cty.Bool, Required: false},
"vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false}, "vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false},

View File

@ -22,19 +22,37 @@ func (s *stepCreateDisk) Run(ctx context.Context, state multistep.StateBag) mult
driver := state.Get("driver").(vboxcommon.Driver) driver := state.Get("driver").(vboxcommon.Driver)
ui := state.Get("ui").(packersdk.Ui) ui := state.Get("ui").(packersdk.Ui)
vmName := state.Get("vmName").(string) vmName := state.Get("vmName").(string)
format := "VDI" format := "VDI"
path := filepath.Join(config.OutputDir, fmt.Sprintf("%s.%s", config.VMName, strings.ToLower(format)))
// The main disk and additional disks
diskFullPaths := []string{}
diskSizes := []uint{config.DiskSize}
if len(config.AdditionalDiskSize) == 0 {
// If there are no additional disks, use disk naming as before
diskFullPaths = append(diskFullPaths, filepath.Join(config.OutputDir, fmt.Sprintf("%s.%s", config.VMName, strings.ToLower(format))))
} else {
// If there are additional disks, use consistent naming with numbers
diskFullPaths = append(diskFullPaths, filepath.Join(config.OutputDir, fmt.Sprintf("%s-0.%s", config.VMName, strings.ToLower(format))))
for i, diskSize := range config.AdditionalDiskSize {
path := filepath.Join(config.OutputDir, fmt.Sprintf("%s-%d.%s", config.VMName, i+1, strings.ToLower(format)))
diskFullPaths = append(diskFullPaths, path)
diskSizes = append(diskSizes, diskSize)
}
}
// Create all required disks
for i := range diskFullPaths {
ui.Say(fmt.Sprintf("Creating hard drive %s with size %d MiB...", diskFullPaths[i], diskSizes[i]))
command := []string{ command := []string{
"createhd", "createhd",
"--filename", path, "--filename", diskFullPaths[i],
"--size", strconv.FormatUint(uint64(config.DiskSize), 10), "--size", strconv.FormatUint(uint64(diskSizes[i]), 10),
"--format", format, "--format", format,
"--variant", "Standard", "--variant", "Standard",
} }
ui.Say("Creating hard drive...")
err := driver.VBoxManage(command...) err := driver.VBoxManage(command...)
if err != nil { if err != nil {
err := fmt.Errorf("Error creating hard drive: %s", err) err := fmt.Errorf("Error creating hard drive: %s", err)
@ -42,11 +60,12 @@ func (s *stepCreateDisk) Run(ctx context.Context, state multistep.StateBag) mult
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
} }
}
// Add the IDE controller so we can later attach the disk. // Add the IDE controller so we can later attach the disk.
// When the hard disk controller is not IDE, this device is still used // When the hard disk controller is not IDE, this device is still used
// by VirtualBox to deliver the guest extensions. // by VirtualBox to deliver the guest extensions.
err = driver.VBoxManage("storagectl", vmName, "--name", "IDE Controller", "--add", "ide") err := driver.VBoxManage("storagectl", vmName, "--name", "IDE Controller", "--add", "ide")
if err != nil { if err != nil {
err := fmt.Errorf("Error creating disk controller: %s", err) err := fmt.Errorf("Error creating disk controller: %s", err)
state.Put("error", err) state.Put("error", err)
@ -116,13 +135,14 @@ func (s *stepCreateDisk) Run(ctx context.Context, state multistep.StateBag) mult
discard = "on" discard = "on"
} }
command = []string{ for i := range diskFullPaths {
command := []string{
"storageattach", vmName, "storageattach", vmName,
"--storagectl", controllerName, "--storagectl", controllerName,
"--port", "0", "--port", strconv.FormatUint(uint64(i), 10),
"--device", "0", "--device", "0",
"--type", "hdd", "--type", "hdd",
"--medium", path, "--medium", diskFullPaths[i],
"--nonrotational", nonrotational, "--nonrotational", nonrotational,
"--discard", discard, "--discard", discard,
} }
@ -132,6 +152,7 @@ func (s *stepCreateDisk) Run(ctx context.Context, state multistep.StateBag) mult
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
} }
}
return multistep.ActionContinue return multistep.ActionContinue
} }

View File

@ -103,6 +103,12 @@
When set to sata, the drive is attached to an AHCI SATA controller. When set to sata, the drive is attached to an AHCI SATA controller.
When set to virtio, the drive is attached to a VirtIO controller. When set to virtio, the drive is attached to a VirtIO controller.
- `disk_additional_size` ([]uint) - Additional disks to create. Uses `vm_name` as the disk name template and
appends `-#` where `#` is the position in the array. `#` starts at 1 since 0
is the default disk. Each value represents the disk image size in MiB.
Each additional disk uses the same disk parameters as the default disk.
Unset by default.
- `keep_registered` (bool) - Set this to true if you would like to keep the VM registered with - `keep_registered` (bool) - Set this to true if you would like to keep the VM registered with
virtualbox. Defaults to false. virtualbox. Defaults to false.