diff --git a/builder/qemu/builder.go b/builder/qemu/builder.go index eb38ba0c7..2e7e107d7 100644 --- a/builder/qemu/builder.go +++ b/builder/qemu/builder.go @@ -88,6 +88,8 @@ type Config struct { DiskSize uint `mapstructure:"disk_size"` DiskCache string `mapstructure:"disk_cache"` DiskDiscard string `mapstructure:"disk_discard"` + SkipCompaction bool `mapstructure:"skip_compaction"` + DiskCompression bool `mapstructure:"disk_compression"` FloppyFiles []string `mapstructure:"floppy_files"` Format string `mapstructure:"format"` Headless bool `mapstructure:"headless"` @@ -242,6 +244,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { errs, errors.New("invalid format, only 'qcow2' or 'raw' are allowed")) } + if b.config.Format != "qcow2" { + b.config.SkipCompaction = true + b.config.DiskCompression = false + } + if _, ok := accels[b.config.Accelerator]; !ok { errs = packer.MultiErrorAppend( errs, errors.New("invalid accelerator, only 'kvm', 'tcg', 'xen', or 'none' are allowed")) @@ -364,6 +371,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe }, new(common.StepProvision), new(stepShutdown), + new(stepConvertDisk), } // Setup the state bag diff --git a/builder/qemu/step_convert_disk.go b/builder/qemu/step_convert_disk.go new file mode 100644 index 000000000..dcf5e97de --- /dev/null +++ b/builder/qemu/step_convert_disk.go @@ -0,0 +1,67 @@ +package qemu + +import ( + "fmt" + "path/filepath" + + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + + "os" +) + +// This step converts the virtual disk that was used as the +// hard drive for the virtual machine. +type stepConvertDisk struct{} + +func (s *stepConvertDisk) Run(state multistep.StateBag) multistep.StepAction { + config := state.Get("config").(*Config) + driver := state.Get("driver").(Driver) + diskName := state.Get("disk_filename").(string) + ui := state.Get("ui").(packer.Ui) + + if config.SkipCompaction && !config.DiskCompression { + return multistep.ActionContinue + } + + name := diskName + ".convert" + + sourcePath := filepath.Join(config.OutputDir, diskName) + targetPath := filepath.Join(config.OutputDir, name) + + command := []string{ + "convert", + "-q", + } + + if config.DiskCompression { + command = append(command, "-c") + } + + command = append(command, []string{ + "-f", config.Format, + "-O", config.Format, + sourcePath, + targetPath, + }..., + ) + + ui.Say("Converting hard drive...") + if err := driver.QemuImg(command...); err != nil { + err := fmt.Errorf("Error converting hard drive: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + if err := os.Rename(targetPath, sourcePath); err != nil { + err := fmt.Errorf("Error moving converted hard drive: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + return multistep.ActionContinue +} + +func (s *stepConvertDisk) Cleanup(state multistep.StateBag) {} diff --git a/website/source/docs/builders/qemu.html.markdown b/website/source/docs/builders/qemu.html.markdown index 13ad4bda2..5cfc767d3 100644 --- a/website/source/docs/builders/qemu.html.markdown +++ b/website/source/docs/builders/qemu.html.markdown @@ -136,6 +136,12 @@ builder. - `disk_size` (integer) - The size, in megabytes, of the hard disk to create for the VM. By default, this is 40000 (about 40 GB). +- `skip_compaction` (boolean) - Packer compacts the QCOW2 image using `qemu-img convert`. + Set this option to `true` to disable compacting. Defaults to `false`. + +- `disk_compression` (boolean) - Apply compression to the QCOW2 disk file + using `qemu-img convert`. Defaults to `false`. + - `floppy_files` (array of strings) - A list of files to place onto a floppy disk that is attached when the VM is booted. This is most useful for unattended Windows installs, which look for an `Autounattend.xml` file on