Add additional disk support for QEMU builder.

This commit is contained in:
Jayson Cofell 2019-06-24 17:35:06 -06:00
parent 757bd4bed9
commit c9b693080a
6 changed files with 97 additions and 38 deletions

View File

@ -99,6 +99,7 @@ type Config struct {
ISOSkipCache bool `mapstructure:"iso_skip_cache"`
Accelerator string `mapstructure:"accelerator"`
CpuCount int `mapstructure:"cpus"`
AdditionalDiskSize []string `mapstructure:"disk_additional_size"`
DiskInterface string `mapstructure:"disk_interface"`
DiskSize uint `mapstructure:"disk_size"`
DiskCache string `mapstructure:"disk_cache"`
@ -286,6 +287,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
errs, errors.New("use_backing_file can only be enabled for QCOW2 images and when disk_image is true"))
}
if b.config.DiskImage && len(b.config.AdditionalDiskSize) > 0 {
errs = packer.MultiErrorAppend(
errs, errors.New("disk_additional_size can only be used when disk_image is false"))
}
if _, ok := accels[b.config.Accelerator]; !ok {
errs = packer.MultiErrorAppend(
errs, errors.New("invalid accelerator, only 'kvm', 'tcg', 'xen', 'hax', 'hvf', 'whpx', or 'none' are allowed"))
@ -500,7 +506,11 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
state: make(map[string]interface{}),
}
artifact.state["diskName"] = state.Get("disk_filename").(string)
artifact.state["diskName"] = b.config.VMName
diskpaths, ok := state.Get("qemu_disk_paths").([]string)
if ok {
artifact.state["diskPaths"] = diskpaths
}
artifact.state["diskType"] = b.config.Format
artifact.state["diskSize"] = uint64(b.config.DiskSize)
artifact.state["domainType"] = b.config.Accelerator

View File

@ -22,7 +22,7 @@ type stepConvertDisk struct{}
func (s *stepConvertDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
driver := state.Get("driver").(Driver)
diskName := state.Get("disk_filename").(string)
diskName := config.VMName
ui := state.Get("ui").(packer.Ui)
if config.SkipCompaction && !config.DiskCompression {

View File

@ -19,7 +19,6 @@ func (s *stepCopyDisk) Run(ctx context.Context, state multistep.StateBag) multis
isoPath := state.Get("iso_path").(string)
ui := state.Get("ui").(packer.Ui)
path := filepath.Join(config.OutputDir, fmt.Sprintf("%s", config.VMName))
name := config.VMName
command := []string{
"convert",
@ -40,8 +39,6 @@ func (s *stepCopyDisk) Run(ctx context.Context, state multistep.StateBag) multis
return multistep.ActionHalt
}
state.Put("disk_filename", name)
return multistep.ActionContinue
}

View File

@ -3,6 +3,7 @@ package qemu
import (
"context"
"fmt"
"log"
"path/filepath"
"github.com/hashicorp/packer/helper/multistep"
@ -18,36 +19,54 @@ func (s *stepCreateDisk) Run(ctx context.Context, state multistep.StateBag) mult
driver := state.Get("driver").(Driver)
ui := state.Get("ui").(packer.Ui)
name := config.VMName
path := filepath.Join(config.OutputDir, name)
command := []string{
"create",
"-f", config.Format,
}
if config.UseBackingFile {
isoPath := state.Get("iso_path").(string)
command = append(command, "-b", isoPath)
}
command = append(command,
path,
fmt.Sprintf("%vM", config.DiskSize),
)
if config.DiskImage && !config.UseBackingFile {
return multistep.ActionContinue
}
ui.Say("Creating hard drive...")
if err := driver.QemuImg(command...); err != nil {
err := fmt.Errorf("Error creating hard drive: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
var diskFullPaths, diskSizes []string
ui.Say("Creating required virtual machine disks")
// The 'main' or 'default' disk
diskFullPaths = append(diskFullPaths, filepath.Join(config.OutputDir, name))
diskSizes = append(diskSizes, fmt.Sprintf("%dM", uint64(config.DiskSize)))
// Additional disks
if len(config.AdditionalDiskSize) > 0 {
for i, diskSize := range config.AdditionalDiskSize {
path := filepath.Join(config.OutputDir, fmt.Sprintf("%s-%d", name, i+1))
diskFullPaths = append(diskFullPaths, path)
size := fmt.Sprintf("%s", diskSize)
diskSizes = append(diskSizes, size)
}
}
state.Put("disk_filename", name)
// Create all required disks
for i, diskFullPath := range diskFullPaths {
log.Printf("[INFO] Creating disk with Path: %s and Size: %s", diskFullPath, diskSizes[i])
command := []string{
"create",
"-f", config.Format,
}
if config.UseBackingFile && i == 0 {
isoPath := state.Get("iso_path").(string)
command = append(command, "-b", isoPath)
}
command = append(command,
diskFullPath,
diskSizes[i])
if err := driver.QemuImg(command...); err != nil {
err := fmt.Errorf("Error creating hard drive: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
// Stash the disk paths so we can retrieve later
state.Put("qemu_disk_paths", diskFullPaths)
return multistep.ActionContinue
}

View File

@ -94,19 +94,42 @@ func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error
if qemuVersion.GreaterThanOrEqual(v2) {
if config.DiskInterface == "virtio-scsi" {
deviceArgs = append(deviceArgs, "virtio-scsi-pci,id=scsi0", "scsi-hd,bus=scsi0.0,drive=drive0")
driveArgumentString := fmt.Sprintf("if=none,file=%s,id=drive0,cache=%s,discard=%s,format=%s", imgPath, config.DiskCache, config.DiskDiscard, config.Format)
if config.DetectZeroes != "off" {
driveArgumentString = fmt.Sprintf("%s,detect-zeroes=%s", driveArgumentString, config.DetectZeroes)
if config.DiskImage {
deviceArgs = append(deviceArgs, "virtio-scsi-pci,id=scsi0", "scsi-hd,bus=scsi0.0,drive=drive0")
driveArgumentString := fmt.Sprintf("if=none,file=%s,id=drive0,cache=%s,discard=%s,format=%s", imgPath, config.DiskCache, config.DiskDiscard, config.Format)
if config.DetectZeroes != "off" {
driveArgumentString = fmt.Sprintf("%s,detect-zeroes=%s", driveArgumentString, config.DetectZeroes)
}
driveArgs = append(driveArgs, driveArgumentString)
} else {
deviceArgs = append(deviceArgs, "virtio-scsi-pci,id=scsi0")
diskFullPaths := state.Get("qemu_disk_paths").([]string)
for i, diskFullPath := range diskFullPaths {
deviceArgs = append(deviceArgs, fmt.Sprintf("scsi-hd,bus=scsi0.0,drive=drive%d", i))
driveArgumentString := fmt.Sprintf("if=none,file=%s,id=drive%d,cache=%s,discard=%s,format=%s", diskFullPath, i, config.DiskCache, config.DiskDiscard, config.Format)
if config.DetectZeroes != "off" {
driveArgumentString = fmt.Sprintf("%s,detect-zeroes=%s", driveArgumentString, config.DetectZeroes)
}
driveArgs = append(driveArgs, driveArgumentString)
}
}
driveArgs = append(driveArgs, driveArgumentString)
} else {
driveArgumentString := fmt.Sprintf("file=%s,if=%s,cache=%s,discard=%s,format=%s", imgPath, config.DiskInterface, config.DiskCache, config.DiskDiscard, config.Format)
if config.DetectZeroes != "off" {
driveArgumentString = fmt.Sprintf("%s,detect-zeroes=%s", driveArgumentString, config.DetectZeroes)
if config.DiskImage {
driveArgumentString := fmt.Sprintf("file=%s,if=%s,cache=%s,discard=%s,format=%s", imgPath, config.DiskInterface, config.DiskCache, config.DiskDiscard, config.Format)
if config.DetectZeroes != "off" {
driveArgumentString = fmt.Sprintf("%s,detect-zeroes=%s", driveArgumentString, config.DetectZeroes)
}
driveArgs = append(driveArgs, driveArgumentString)
} else {
diskFullPaths := state.Get("qemu_disk_paths").([]string)
for _, diskFullPath := range diskFullPaths {
driveArgumentString := fmt.Sprintf("file=%s,if=%s,cache=%s,discard=%s,format=%s", diskFullPath, config.DiskInterface, config.DiskCache, config.DiskDiscard, config.Format)
if config.DetectZeroes != "off" {
driveArgumentString = fmt.Sprintf("%s,detect-zeroes=%s", driveArgumentString, config.DetectZeroes)
}
driveArgs = append(driveArgs, driveArgumentString)
}
}
driveArgs = append(driveArgs, driveArgumentString)
}
} else {
driveArgs = append(driveArgs, fmt.Sprintf("file=%s,if=%s,cache=%s,format=%s", imgPath, config.DiskInterface, config.DiskCache, config.Format))

View File

@ -142,6 +142,16 @@ Linux server and have not enabled X11 forwarding (`ssh -X`).
- `cpus` (number) - The number of cpus to use when building the VM.
The default is `1` CPU.
- `disk_additional_size` (array of strings) - 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 string represents the disk image size in bytes. Optional suffixes
'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M),
'T' (terabyte, 1024G), 'P' (petabyte, 1024T) and 'E' (exabyte, 1024P) are
supported. 'b' is ignored. Per qemu-img documentation.
Each additional disk uses the same disk parameters as the default disk.
Unset by default.
- `disk_cache` (string) - The cache mode to use for disk. Allowed values
include any of `writethrough`, `writeback`, `none`, `unsafe`
or `directsync`. By default, this is set to `writeback`.