From 3aebd5f462a02be77821954e4c324c9bb9a7aed5 Mon Sep 17 00:00:00 2001 From: Adam Robinson Date: Fri, 20 Apr 2018 15:13:12 -0400 Subject: [PATCH] Add use_fixed_vhd_format Hyper-V ISO option --- builder/hyperv/common/driver.go | 2 +- builder/hyperv/common/driver_mock.go | 3 +- builder/hyperv/common/driver_ps_4.go | 4 +- builder/hyperv/common/step_create_vm.go | 3 +- builder/hyperv/iso/builder.go | 24 ++++++++- builder/hyperv/iso/builder_test.go | 53 +++++++++++++++++++ common/powershell/hyperv/hyperv.go | 20 +++++-- .../docs/builders/hyperv-iso.html.md.erb | 6 +++ 8 files changed, 104 insertions(+), 11 deletions(-) diff --git a/builder/hyperv/common/driver.go b/builder/hyperv/common/driver.go index e7b58464e..65ca8a314 100644 --- a/builder/hyperv/common/driver.go +++ b/builder/hyperv/common/driver.go @@ -66,7 +66,7 @@ type Driver interface { DeleteVirtualSwitch(string) error - CreateVirtualMachine(string, string, string, string, int64, int64, int64, string, uint, bool) error + CreateVirtualMachine(string, string, string, string, int64, int64, int64, string, uint, bool, bool) error AddVirtualMachineHardDrive(string, string, string, int64, int64, string) error diff --git a/builder/hyperv/common/driver_mock.go b/builder/hyperv/common/driver_mock.go index 8af637e66..fce4a8710 100644 --- a/builder/hyperv/common/driver_mock.go +++ b/builder/hyperv/common/driver_mock.go @@ -127,6 +127,7 @@ type DriverMock struct { CreateVirtualMachine_SwitchName string CreateVirtualMachine_Generation uint CreateVirtualMachine_DifferentialDisk bool + CreateVirtualMachine_FixedVHD bool CreateVirtualMachine_Err error CloneVirtualMachine_Called bool @@ -390,7 +391,7 @@ func (d *DriverMock) AddVirtualMachineHardDrive(vmName string, vhdFile string, v return d.AddVirtualMachineHardDrive_Err } -func (d *DriverMock) CreateVirtualMachine(vmName string, path string, harddrivePath string, vhdPath string, ram int64, diskSize int64, diskBlockSize int64, switchName string, generation uint, diffDisks bool) error { +func (d *DriverMock) CreateVirtualMachine(vmName string, path string, harddrivePath string, vhdPath string, ram int64, diskSize int64, diskBlockSize int64, switchName string, generation uint, diffDisks bool, fixedVHD bool) error { d.CreateVirtualMachine_Called = true d.CreateVirtualMachine_VmName = vmName d.CreateVirtualMachine_Path = path diff --git a/builder/hyperv/common/driver_ps_4.go b/builder/hyperv/common/driver_ps_4.go index 34a9edbb5..492761ecb 100644 --- a/builder/hyperv/common/driver_ps_4.go +++ b/builder/hyperv/common/driver_ps_4.go @@ -178,8 +178,8 @@ func (d *HypervPS4Driver) AddVirtualMachineHardDrive(vmName string, vhdFile stri return hyperv.AddVirtualMachineHardDiskDrive(vmName, vhdFile, vhdName, vhdSizeBytes, diskBlockSize, controllerType) } -func (d *HypervPS4Driver) CreateVirtualMachine(vmName string, path string, harddrivePath string, vhdPath string, ram int64, diskSize int64, diskBlockSize int64, switchName string, generation uint, diffDisks bool) error { - return hyperv.CreateVirtualMachine(vmName, path, harddrivePath, vhdPath, ram, diskSize, diskBlockSize, switchName, generation, diffDisks) +func (d *HypervPS4Driver) CreateVirtualMachine(vmName string, path string, harddrivePath string, vhdPath string, ram int64, diskSize int64, diskBlockSize int64, switchName string, generation uint, diffDisks bool, fixedVHD bool) error { + return hyperv.CreateVirtualMachine(vmName, path, harddrivePath, vhdPath, ram, diskSize, diskBlockSize, switchName, generation, diffDisks, fixedVHD) } func (d *HypervPS4Driver) CloneVirtualMachine(cloneFromVmxcPath string, cloneFromVmName string, cloneFromSnapshotName string, cloneAllSnapshots bool, vmName string, path string, harddrivePath string, ram int64, switchName string) error { diff --git a/builder/hyperv/common/step_create_vm.go b/builder/hyperv/common/step_create_vm.go index f8125ed91..a37c1c055 100644 --- a/builder/hyperv/common/step_create_vm.go +++ b/builder/hyperv/common/step_create_vm.go @@ -33,6 +33,7 @@ type StepCreateVM struct { MacAddress string SkipExport bool OutputDir string + FixedVHD bool } func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { @@ -67,7 +68,7 @@ func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multiste diskSize := int64(s.DiskSize * 1024 * 1024) diskBlockSize := int64(s.DiskBlockSize * 1024 * 1024) - err := driver.CreateVirtualMachine(s.VMName, path, harddrivePath, vhdPath, ramSize, diskSize, diskBlockSize, s.SwitchName, s.Generation, s.DifferencingDisk) + err := driver.CreateVirtualMachine(s.VMName, path, harddrivePath, vhdPath, ramSize, diskSize, diskBlockSize, s.SwitchName, s.Generation, s.DifferencingDisk, s.FixedVHD) if err != nil { err := fmt.Errorf("Error creating virtual machine: %s", err) state.Put("error", err) diff --git a/builder/hyperv/iso/builder.go b/builder/hyperv/iso/builder.go index 816299cbc..882e88e47 100644 --- a/builder/hyperv/iso/builder.go +++ b/builder/hyperv/iso/builder.go @@ -24,6 +24,7 @@ const ( DefaultDiskSize = 40 * 1024 // ~40GB MinDiskSize = 256 // 256MB MaxDiskSize = 64 * 1024 * 1024 // 64TB + MaxVHDSize = 2040 * 1024 // 2040GB DefaultDiskBlockSize = 32 // 32MB MinDiskBlockSize = 1 // 1MB @@ -110,6 +111,9 @@ type Config struct { // Use differencing disk DifferencingDisk bool `mapstructure:"differencing_disk"` + // Create the VM with a Fixed VHD format disk instead of Dynamic VHDX + FixedVHD bool `mapstructure:"use_fixed_vhd_format"` + ctx interpolate.Context } @@ -270,6 +274,21 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { } } + if b.config.Generation > 1 && b.config.FixedVHD { + err = errors.New("Fixed VHD disks are only supported on Generation 1 virtual machines.") + errs = packer.MultiErrorAppend(errs, err) + } + + if !b.config.SkipCompaction && b.config.FixedVHD { + err = errors.New("Fixed VHD disks do not support compaction.") + errs = packer.MultiErrorAppend(errs, err) + } + + if b.config.DifferencingDisk && b.config.FixedVHD { + err = errors.New("Fixed VHD disks are not supported with differencing disks.") + errs = packer.MultiErrorAppend(errs, err) + } + // Warnings if b.config.ShutdownCommand == "" { @@ -379,6 +398,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe SkipExport: b.config.SkipExport, OutputDir: b.config.OutputDir, MacAddress: b.config.MacAddress, + FixedVHD: b.config.FixedVHD, }, &hypervcommon.StepEnableIntegrationService{}, @@ -501,8 +521,10 @@ func (b *Builder) checkDiskSize() error { if b.config.DiskSize < MinDiskSize { return fmt.Errorf("disk_size: Virtual machine requires disk space >= %v GB, but defined: %v", MinDiskSize, b.config.DiskSize/1024) - } else if b.config.DiskSize > MaxDiskSize { + } else if b.config.DiskSize > MaxDiskSize && !b.config.FixedVHD { return fmt.Errorf("disk_size: Virtual machine requires disk space <= %v GB, but defined: %v", MaxDiskSize, b.config.DiskSize/1024) + } else if b.config.DiskSize > MaxVHDSize && b.config.FixedVHD { + return fmt.Errorf("disk_size: Virtual machine requires disk space <= %v GB, but defined: %v", MaxVHDSize/1024, b.config.DiskSize/1024) } return nil diff --git a/builder/hyperv/iso/builder_test.go b/builder/hyperv/iso/builder_test.go index 1663b4727..4a63f3c67 100644 --- a/builder/hyperv/iso/builder_test.go +++ b/builder/hyperv/iso/builder_test.go @@ -139,6 +139,59 @@ func TestBuilderPrepare_DiskBlockSize(t *testing.T) { } } +func TestBuilderPrepare_FixedVHDFormat(t *testing.T) { + var b Builder + config := testConfig() + config["use_fixed_vhd_format"] = true + config["generation"] = 1 + config["skip_compaction"] = true + config["differencing_disk"] = false + + //use_fixed_vhd_format should work with generation = 1, skip_compaction = true, and differencing_disk = false + warns, err := b.Prepare(config) + if len(warns) > 0 { + t.Fatalf("bad: %#v", warns) + } + if err != nil { + t.Fatalf("bad err: %s", err) + } + + //use_fixed_vhd_format should not work with differencing_disk = true + config["differencing_disk"] = true + b = Builder{} + warns, err = b.Prepare(config) + if len(warns) > 0 { + t.Fatalf("bad: %#v", warns) + } + if err == nil { + t.Fatal("should have error") + } + config["differencing_disk"] = false + + //use_fixed_vhd_format should not work with skip_compaction = false + config["skip_compaction"] = false + b = Builder{} + warns, err = b.Prepare(config) + if len(warns) > 0 { + t.Fatalf("bad: %#v", warns) + } + if err == nil { + t.Fatal("should have error") + } + config["skip_compaction"] = true + + //use_fixed_vhd_format should not work with generation = 2 + config["generation"] = 2 + b = Builder{} + warns, err = b.Prepare(config) + if len(warns) > 0 { + t.Fatalf("bad: %#v", warns) + } + if err == nil { + t.Fatal("should have error") + } +} + func TestBuilderPrepare_FloppyFiles(t *testing.T) { var b Builder config := testConfig() diff --git a/common/powershell/hyperv/hyperv.go b/common/powershell/hyperv/hyperv.go index 50eb7cb1a..df0375bbd 100644 --- a/common/powershell/hyperv/hyperv.go +++ b/common/powershell/hyperv/hyperv.go @@ -187,7 +187,7 @@ Hyper-V\Set-VMFloppyDiskDrive -VMName $vmName -Path $null return err } -func CreateVirtualMachine(vmName string, path string, harddrivePath string, vhdRoot string, ram int64, diskSize int64, diskBlockSize int64, switchName string, generation uint, diffDisks bool) error { +func CreateVirtualMachine(vmName string, path string, harddrivePath string, vhdRoot string, ram int64, diskSize int64, diskBlockSize int64, switchName string, generation uint, diffDisks bool, fixedVHD bool) error { if generation == 2 { var script = ` @@ -214,8 +214,13 @@ if ($harddrivePath){ return DisableAutomaticCheckpoints(vmName) } else { var script = ` -param([string]$vmName, [string]$path, [string]$harddrivePath, [string]$vhdRoot, [long]$memoryStartupBytes, [long]$newVHDSizeBytes, [long]$vhdBlockSizeBytes, [string]$switchName, [string]$diffDisks) -$vhdx = $vmName + '.vhdx' +param([string]$vmName, [string]$path, [string]$harddrivePath, [string]$vhdRoot, [long]$memoryStartupBytes, [long]$newVHDSizeBytes, [long]$vhdBlockSizeBytes, [string]$switchName, [string]$diffDisks, [string]$fixedVHD) +if($fixedVHD -eq "true"){ + $vhdx = $vmName + '.vhd' +} +else{ + $vhdx = $vmName + '.vhdx' +} $vhdPath = Join-Path -Path $vhdRoot -ChildPath $vhdx if ($harddrivePath){ if($diffDisks -eq "true"){ @@ -226,12 +231,17 @@ if ($harddrivePath){ } Hyper-V\New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -VHDPath $vhdPath -SwitchName $switchName } else { - Hyper-V\New-VHD -Path $vhdPath -SizeBytes $newVHDSizeBytes -BlockSizeBytes $vhdBlockSizeBytes + if($fixedVHD -eq "true"){ + Hyper-V\New-VHD -Path $vhdPath -Fixed -SizeBytes $newVHDSizeBytes + } + else { + Hyper-V\New-VHD -Path $vhdPath -SizeBytes $newVHDSizeBytes -BlockSizeBytes $vhdBlockSizeBytes + } Hyper-V\New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -VHDPath $vhdPath -SwitchName $switchName } ` var ps powershell.PowerShellCmd - if err := ps.Run(script, vmName, path, harddrivePath, vhdRoot, strconv.FormatInt(ram, 10), strconv.FormatInt(diskSize, 10), strconv.FormatInt(diskBlockSize, 10), switchName, strconv.FormatBool(diffDisks)); err != nil { + if err := ps.Run(script, vmName, path, harddrivePath, vhdRoot, strconv.FormatInt(ram, 10), strconv.FormatInt(diskSize, 10), strconv.FormatInt(diskBlockSize, 10), switchName, strconv.FormatBool(diffDisks), strconv.FormatBool(fixedVHD)); err != nil { return err } diff --git a/website/source/docs/builders/hyperv-iso.html.md.erb b/website/source/docs/builders/hyperv-iso.html.md.erb index 95bfa6293..a696b09a1 100644 --- a/website/source/docs/builders/hyperv-iso.html.md.erb +++ b/website/source/docs/builders/hyperv-iso.html.md.erb @@ -212,6 +212,12 @@ can be configured for this builder. By default none is set. If none is set then a vlan is not set on the switch's network card. If this value is set it should match the vlan specified in by `vlan_id`. +- `use_fixed_vhd_format` (boolean) - If true, creates the boot disk on the virtual machine as + a fixed VHD format disk. The default is false, which creates a dynamic VHDX format disk. This + option requires setting `generation` to 1, `skip_compaction` to true, and `differencing_disk` to false. + Additionally, any value entered for `disk_block_size` will be ignored. The most likely use case for this + option is outputing a disk that is in the format required for upload to Azure. + - `vhd_temp_path` (string) - A separate path to be used for storing the VM's disk image. The purpose is to enable reading and writing to take place on different physical disks (read from VHD temp path, write to regular temp