Refactor the export step for Hyper-V ISO and VMCX builders

* Fixes a bug that caused the build to error if users did not
  explicitly set `skip_compaction:true` when setting `skip_export:
  true`. See #6392.
* Improves the efficiency of the compaction and export process by
  reordering the compaction and export steps.
* Further improves the efficiency of the compacting step through
  compacting the vmd* file directly rather than creating and then
  operating on a copy.
* The changes mean the export process now stores the exported machine
  files and folders under a folder with name 'vm_name' in the output
  directory. Previously the exported machine files and folders were
  stored directly in the output directory.
This commit is contained in:
DanHam 2018-06-16 18:02:38 +01:00
parent a5a6b1ab58
commit 3fc2defb6d
No known key found for this signature in database
GPG Key ID: 58E79AEDD6AA987E
5 changed files with 38 additions and 62 deletions

View File

@ -94,7 +94,7 @@ type Driver interface {
ExportVirtualMachine(string, string) error ExportVirtualMachine(string, string) error
CompactDisks(string, string) error CompactDisks(string) error
CopyExportedVirtualMachine(string, string, string, string) error CopyExportedVirtualMachine(string, string, string, string) error

View File

@ -186,10 +186,9 @@ type DriverMock struct {
ExportVirtualMachine_Path string ExportVirtualMachine_Path string
ExportVirtualMachine_Err error ExportVirtualMachine_Err error
CompactDisks_Called bool CompactDisks_Called bool
CompactDisks_ExpPath string CompactDisks_Path string
CompactDisks_VhdDir string CompactDisks_Err error
CompactDisks_Err error
CopyExportedVirtualMachine_Called bool CopyExportedVirtualMachine_Called bool
CopyExportedVirtualMachine_ExpPath string CopyExportedVirtualMachine_ExpPath string
@ -489,10 +488,9 @@ func (d *DriverMock) ExportVirtualMachine(vmName string, path string) error {
return d.ExportVirtualMachine_Err return d.ExportVirtualMachine_Err
} }
func (d *DriverMock) CompactDisks(expPath string, vhdDir string) error { func (d *DriverMock) CompactDisks(path string) error {
d.CompactDisks_Called = true d.CompactDisks_Called = true
d.CompactDisks_ExpPath = expPath d.CompactDisks_Path = path
d.CompactDisks_VhdDir = vhdDir
return d.CompactDisks_Err return d.CompactDisks_Err
} }

View File

@ -219,8 +219,8 @@ func (d *HypervPS4Driver) ExportVirtualMachine(vmName string, path string) error
return hyperv.ExportVirtualMachine(vmName, path) return hyperv.ExportVirtualMachine(vmName, path)
} }
func (d *HypervPS4Driver) CompactDisks(expPath string, vhdDir string) error { func (d *HypervPS4Driver) CompactDisks(path string) error {
return hyperv.CompactDisks(expPath, vhdDir) return hyperv.CompactDisks(path)
} }
func (d *HypervPS4Driver) CopyExportedVirtualMachine(expPath string, outputPath string, vhdDir string, vmDir string) error { func (d *HypervPS4Driver) CopyExportedVirtualMachine(expPath string, outputPath string, vhdDir string, vmDir string) error {

View File

@ -3,18 +3,11 @@ package common
import ( import (
"context" "context"
"fmt" "fmt"
"io/ioutil"
"path/filepath"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
) )
const (
vhdDir string = "Virtual Hard Disks"
vmDir string = "Virtual Machines"
)
type StepExportVm struct { type StepExportVm struct {
OutputDir string OutputDir string
SkipCompaction bool SkipCompaction bool
@ -24,63 +17,48 @@ type StepExportVm struct {
func (s *StepExportVm) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { func (s *StepExportVm) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
driver := state.Get("driver").(Driver) driver := state.Get("driver").(Driver)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
var err error
var errorMsg string
vmName := state.Get("vmName").(string) // Get the VM name; Get the temp directory used to store the VMs files
tmpPath := state.Get("packerTempDir").(string) // during the build process
outputPath := s.OutputDir var vmName, tmpPath string
expPath := s.OutputDir if v, ok := state.GetOk("vmName"); ok {
vmName = v.(string)
// create temp path to export vm
errorMsg = "Error creating temp export path: %s"
vmExportPath, err := ioutil.TempDir(tmpPath, "export")
if err != nil {
err := fmt.Errorf(errorMsg, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
} }
if !s.SkipExport { if v, ok := state.GetOk("packerTempDir"); ok {
ui.Say("Exporting vm...") tmpPath = v.(string)
err = driver.ExportVirtualMachine(vmName, vmExportPath)
if err != nil {
errorMsg = "Error exporting vm: %s"
err := fmt.Errorf(errorMsg, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
// copy to output dir
expPath = filepath.Join(vmExportPath, vmName)
} }
// Compact disks first so the export process has less to do
if s.SkipCompaction { if s.SkipCompaction {
ui.Say("Skipping disk compaction...") ui.Say("Skipping disk compaction...")
} else { } else {
ui.Say("Compacting disks...") ui.Say("Compacting disks...")
err = driver.CompactDisks(expPath, vhdDir) err := driver.CompactDisks(tmpPath)
if err != nil { if err != nil {
errorMsg = "Error compacting disks: %s" err := fmt.Errorf("Error compacting disks: %s", err)
err := fmt.Errorf(errorMsg, err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt
} }
} }
if !s.SkipExport { if s.SkipExport {
ui.Say("Copying to output dir...") ui.Say("Skipping export of virtual machine...")
err = driver.CopyExportedVirtualMachine(expPath, outputPath, vhdDir, vmDir) return multistep.ActionContinue
if err != nil {
errorMsg = "Error exporting vm: %s"
err := fmt.Errorf(errorMsg, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
} }
ui.Say("Exporting virtual machine...")
// The export process exports the VM to a folder named 'vmName' under
// the output directory. This contains the usual 'Snapshots', 'Virtual
// Hard Disks' and 'Virtual Machines' directories.
err := driver.ExportVirtualMachine(vmName, s.OutputDir)
if err != nil {
err = fmt.Errorf("Error exporting vm: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
return multistep.ActionContinue return multistep.ActionContinue
} }

View File

@ -665,16 +665,16 @@ if (Test-Path -Path ([IO.Path]::Combine($path, $vmName, 'Virtual Machines', '*.V
return err return err
} }
func CompactDisks(expPath string, vhdDir string) error { func CompactDisks(path string) error {
var script = ` var script = `
param([string]$srcPath, [string]$vhdDirName) param([string]$srcPath)
Get-ChildItem "$srcPath/$vhdDirName" -Filter *.vhd* | %{ Get-ChildItem "$srcPath" -Filter *.vhd* | %{
Optimize-VHD -Path $_.FullName -Mode Full Optimize-VHD -Path $_.FullName -Mode Full
} }
` `
var ps powershell.PowerShellCmd var ps powershell.PowerShellCmd
err := ps.Run(script, expPath, vhdDir) err := ps.Run(script, path)
return err return err
} }