From 3192f5e0da7752d0ac6a3cb06f28202335d3e75a Mon Sep 17 00:00:00 2001 From: Matt Coleman Date: Wed, 2 May 2018 00:56:13 -0400 Subject: [PATCH] qemu builder: add the 'use_backing_file' setting for QCOW2 images --- builder/qemu/builder.go | 6 +++ builder/qemu/builder_test.go | 43 +++++++++++++++++++ builder/qemu/step_copy_disk.go | 2 +- builder/qemu/step_create_disk.go | 14 ++++-- website/source/docs/builders/qemu.html.md.erb | 11 ++++- 5 files changed, 70 insertions(+), 6 deletions(-) diff --git a/builder/qemu/builder.go b/builder/qemu/builder.go index d664dade9..fa2f1f9d9 100644 --- a/builder/qemu/builder.go +++ b/builder/qemu/builder.go @@ -99,6 +99,7 @@ type Config struct { Format string `mapstructure:"format"` Headless bool `mapstructure:"headless"` DiskImage bool `mapstructure:"disk_image"` + UseBackingFile bool `mapstructure:"use_backing_file"` MachineType string `mapstructure:"machine_type"` NetDevice string `mapstructure:"net_device"` OutputDir string `mapstructure:"output_directory"` @@ -255,6 +256,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { b.config.DiskCompression = false } + if b.config.UseBackingFile && !(b.config.DiskImage && b.config.Format == "qcow2") { + errs = packer.MultiErrorAppend( + errs, errors.New("use_backing_file can only be enabled for QCOW2 images and when disk_image is true")) + } + if _, ok := accels[b.config.Accelerator]; !ok { errs = packer.MultiErrorAppend( errs, errors.New("invalid accelerator, only 'kvm', 'tcg', 'xen', 'hax', 'hvf', or 'none' are allowed")) diff --git a/builder/qemu/builder_test.go b/builder/qemu/builder_test.go index 4ddfa1560..d0d403666 100644 --- a/builder/qemu/builder_test.go +++ b/builder/qemu/builder_test.go @@ -224,6 +224,49 @@ func TestBuilderPrepare_Format(t *testing.T) { } } +func TestBuilderPrepare_UseBackingFile(t *testing.T) { + var b Builder + config := testConfig() + + config["use_backing_file"] = true + + // Bad: iso_url is not a disk_image + config["disk_image"] = false + config["format"] = "qcow2" + b = Builder{} + warns, err := b.Prepare(config) + if len(warns) > 0 { + t.Fatalf("bad: %#v", warns) + } + if err == nil { + t.Fatal("should have error") + } + + // Bad: format is not 'qcow2' + config["disk_image"] = true + config["format"] = "raw" + b = Builder{} + warns, err = b.Prepare(config) + if len(warns) > 0 { + t.Fatalf("bad: %#v", warns) + } + if err == nil { + t.Fatal("should have error") + } + + // Good: iso_url is a disk image and format is 'qcow2' + config["disk_image"] = true + config["format"] = "qcow2" + b = Builder{} + warns, err = b.Prepare(config) + if len(warns) > 0 { + t.Fatalf("bad: %#v", warns) + } + if err != nil { + t.Fatalf("should not have error: %s", err) + } +} + func TestBuilderPrepare_FloppyFiles(t *testing.T) { var b Builder config := testConfig() diff --git a/builder/qemu/step_copy_disk.go b/builder/qemu/step_copy_disk.go index 51ca47a1d..3f1c33ffb 100644 --- a/builder/qemu/step_copy_disk.go +++ b/builder/qemu/step_copy_disk.go @@ -28,7 +28,7 @@ func (s *stepCopyDisk) Run(_ context.Context, state multistep.StateBag) multiste path, } - if config.DiskImage == false { + if !config.DiskImage || config.UseBackingFile { return multistep.ActionContinue } diff --git a/builder/qemu/step_create_disk.go b/builder/qemu/step_create_disk.go index 4472903f1..0a18a3c18 100644 --- a/builder/qemu/step_create_disk.go +++ b/builder/qemu/step_create_disk.go @@ -23,11 +23,19 @@ func (s *stepCreateDisk) Run(_ context.Context, state multistep.StateBag) multis command := []string{ "create", "-f", config.Format, - path, - fmt.Sprintf("%vM", config.DiskSize), } - if config.DiskImage == true { + 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 } diff --git a/website/source/docs/builders/qemu.html.md.erb b/website/source/docs/builders/qemu.html.md.erb index 5d6de7e45..df7b08af2 100644 --- a/website/source/docs/builders/qemu.html.md.erb +++ b/website/source/docs/builders/qemu.html.md.erb @@ -152,8 +152,9 @@ Linux server and have not enabled X11 forwarding (`ssh -X`). - `disk_image` (boolean) - Packer defaults to building from an ISO file, this parameter controls whether the ISO URL supplied is actually a bootable - QEMU image. When this value is set to true, the machine will clone the - source, resize it according to `disk_size` and boot the image. + QEMU image. When this value is set to `true`, the machine will either clone + the source or use it as a backing file (if `use_backing_file` is `true`); + then, it will resize the image according to `disk_size` and boot it. - `disk_interface` (string) - The interface to use for the disk. Allowed values include any of `ide`, `scsi`, `virtio` or `virtio-scsi`^\*. Note @@ -319,6 +320,12 @@ will bind to their own SSH port as determined by each process. This will also work with WinRM, just change the port forward in `qemuargs` to map to WinRM's default port of `5985` or whatever value you have the service set to listen on. +- `use_backing_file` (boolean) - Only applicable when `disk_image` is `true` + and `format` is `qcow2`, set this option to `true` to create a new QCOW2 + file that uses the file located at `iso_url` as a backing file. The new file + will only contain blocks that have changed compared to the backing file, so + enabling this option can significantly reduce disk usage. + - `use_default_display` (boolean) - If true, do not pass a `-display` option to qemu, allowing it to choose the default. This may be needed when running under macOS, and getting errors about `sdl` not being available.