Skip to content

Commit

Permalink
Merge pull request #5444 from vijayinvites/packer-vhdx
Browse files Browse the repository at this point in the history
Hyperv vmcx builder and allow vhd/vhdx instead of ISO
  • Loading branch information
SwampDragons authored Oct 13, 2017
2 parents 0a225d3 + 4f6a207 commit f3c3324
Show file tree
Hide file tree
Showing 16 changed files with 2,713 additions and 31 deletions.
6 changes: 5 additions & 1 deletion builder/hyperv/common/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,14 @@ type Driver interface {

DeleteVirtualSwitch(string) error

CreateVirtualMachine(string, string, string, int64, int64, string, uint) error
CreateVirtualMachine(string, string, string, string, int64, int64, string, uint) error

CloneVirtualMachine(string, string, string, bool, string, string, string, int64, string) error

DeleteVirtualMachine(string) error

GetVirtualMachineGeneration(string) (uint, error)

SetVirtualMachineCpuCount(string, uint) error

SetVirtualMachineMacSpoofing(string, bool) error
Expand Down
12 changes: 10 additions & 2 deletions builder/hyperv/common/driver_ps_4.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ func (d *HypervPS4Driver) GetHostName(ip string) (string, error) {
return powershell.GetHostName(ip)
}

func (d *HypervPS4Driver) GetVirtualMachineGeneration(vmName string) (uint, error) {
return hyperv.GetVirtualMachineGeneration(vmName)
}

// Finds the IP address of a host adapter connected to switch
func (d *HypervPS4Driver) GetHostAdapterIpAddressForSwitch(switchName string) (string, error) {
res, err := hyperv.GetHostAdapterIpAddressForSwitch(switchName)
Expand Down Expand Up @@ -166,8 +170,12 @@ func (d *HypervPS4Driver) CreateVirtualSwitch(switchName string, switchType stri
return hyperv.CreateVirtualSwitch(switchName, switchType)
}

func (d *HypervPS4Driver) CreateVirtualMachine(vmName string, path string, vhdPath string, ram int64, diskSize int64, switchName string, generation uint) error {
return hyperv.CreateVirtualMachine(vmName, path, vhdPath, ram, diskSize, switchName, generation)
func (d *HypervPS4Driver) CreateVirtualMachine(vmName string, path string, harddrivePath string, vhdPath string, ram int64, diskSize int64, switchName string, generation uint) error {
return hyperv.CreateVirtualMachine(vmName, path, harddrivePath, vhdPath, ram, diskSize, switchName, generation)
}

func (d *HypervPS4Driver) CloneVirtualMachine(cloneFromVmxcPath string, cloneFromVmName string, cloneFromSnapshotName string, cloneAllSnapshots bool, vmName string, path string, harddrivePath string, ram int64, switchName string) error {
return hyperv.CloneVirtualMachine(cloneFromVmxcPath, cloneFromVmName, cloneFromSnapshotName, cloneAllSnapshots, vmName, path, harddrivePath, ram, switchName)
}

func (d *HypervPS4Driver) DeleteVirtualMachine(vmName string) error {
Expand Down
139 changes: 139 additions & 0 deletions builder/hyperv/common/step_clone_vm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package common

import (
"fmt"
"log"
"path/filepath"
"strings"

"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
)

// This step clones an existing virtual machine.
//
// Produces:
// VMName string - The name of the VM
type StepCloneVM struct {
CloneFromVMXCPath string
CloneFromVMName string
CloneFromSnapshotName string
CloneAllSnapshots bool
VMName string
SwitchName string
RamSize uint
Cpu uint
EnableMacSpoofing bool
EnableDynamicMemory bool
EnableSecureBoot bool
EnableVirtualizationExtensions bool
}

func (s *StepCloneVM) Run(state multistep.StateBag) multistep.StepAction {
driver := state.Get("driver").(Driver)
ui := state.Get("ui").(packer.Ui)
ui.Say("Cloning virtual machine...")

path := state.Get("packerTempDir").(string)

// Determine if we even have an existing virtual harddrive to attach
harddrivePath := ""
if harddrivePathRaw, ok := state.GetOk("iso_path"); ok {
extension := strings.ToLower(filepath.Ext(harddrivePathRaw.(string)))
if extension == ".vhd" || extension == ".vhdx" {
harddrivePath = harddrivePathRaw.(string)
} else {
log.Println("No existing virtual harddrive, not attaching.")
}
} else {
log.Println("No existing virtual harddrive, not attaching.")
}

// convert the MB to bytes
ramSize := int64(s.RamSize * 1024 * 1024)

err := driver.CloneVirtualMachine(s.CloneFromVMXCPath, s.CloneFromVMName, s.CloneFromSnapshotName, s.CloneAllSnapshots, s.VMName, path, harddrivePath, ramSize, s.SwitchName)
if err != nil {
err := fmt.Errorf("Error cloning virtual machine: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}

err = driver.SetVirtualMachineCpuCount(s.VMName, s.Cpu)
if err != nil {
err := fmt.Errorf("Error creating setting virtual machine cpu: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}

if s.EnableDynamicMemory {
err = driver.SetVirtualMachineDynamicMemory(s.VMName, s.EnableDynamicMemory)
if err != nil {
err := fmt.Errorf("Error creating setting virtual machine dynamic memory: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}

if s.EnableMacSpoofing {
err = driver.SetVirtualMachineMacSpoofing(s.VMName, s.EnableMacSpoofing)
if err != nil {
err := fmt.Errorf("Error creating setting virtual machine mac spoofing: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}

generation, err := driver.GetVirtualMachineGeneration(s.VMName)
if err != nil {
err := fmt.Errorf("Error detecting vm generation: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}

if generation == 2 {
err = driver.SetVirtualMachineSecureBoot(s.VMName, s.EnableSecureBoot)
if err != nil {
err := fmt.Errorf("Error setting secure boot: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}

if s.EnableVirtualizationExtensions {
//This is only supported on Windows 10 and Windows Server 2016 onwards
err = driver.SetVirtualMachineVirtualizationExtensions(s.VMName, s.EnableVirtualizationExtensions)
if err != nil {
err := fmt.Errorf("Error creating setting virtual machine virtualization extensions: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}

// Set the final name in the state bag so others can use it
state.Put("vmName", s.VMName)

return multistep.ActionContinue
}

func (s *StepCloneVM) Cleanup(state multistep.StateBag) {
if s.VMName == "" {
return
}

driver := state.Get("driver").(Driver)
ui := state.Get("ui").(packer.Ui)
ui.Say("Unregistering and deleting virtual machine...")

err := driver.DeleteVirtualMachine(s.VMName)
if err != nil {
ui.Error(fmt.Sprintf("Error deleting virtual machine: %s", err))
}
}
21 changes: 19 additions & 2 deletions builder/hyperv/common/step_create_vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package common

import (
"fmt"
"log"
"path/filepath"
"strings"

"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
Expand All @@ -14,6 +17,7 @@ import (
type StepCreateVM struct {
VMName string
SwitchName string
HarddrivePath string
RamSize uint
DiskSize uint
Generation uint
Expand All @@ -30,13 +34,26 @@ func (s *StepCreateVM) Run(state multistep.StateBag) multistep.StepAction {
ui.Say("Creating virtual machine...")

path := state.Get("packerTempDir").(string)
vhdPath := state.Get("packerVhdTempDir").(string)

// Determine if we even have an existing virtual harddrive to attach
harddrivePath := ""
if harddrivePathRaw, ok := state.GetOk("iso_path"); ok {
extension := strings.ToLower(filepath.Ext(harddrivePathRaw.(string)))
if extension == ".vhd" || extension == ".vhdx" {
harddrivePath = harddrivePathRaw.(string)
} else {
log.Println("No existing virtual harddrive, not attaching.")
}
} else {
log.Println("No existing virtual harddrive, not attaching.")
}

vhdPath := state.Get("packerVhdTempDir").(string)
// convert the MB to bytes
ramSize := int64(s.RamSize * 1024 * 1024)
diskSize := int64(s.DiskSize * 1024 * 1024)

err := driver.CreateVirtualMachine(s.VMName, path, vhdPath, ramSize, diskSize, s.SwitchName, s.Generation)
err := driver.CreateVirtualMachine(s.VMName, path, harddrivePath, vhdPath, ramSize, diskSize, s.SwitchName, s.Generation)
if err != nil {
err := fmt.Errorf("Error creating virtual machine: %s", err)
state.Put("error", err)
Expand Down
18 changes: 17 additions & 1 deletion builder/hyperv/common/step_mount_dvddrive.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"github.com/hashicorp/packer/packer"
"github.com/mitchellh/multistep"
"log"
"path/filepath"
"strings"
)

type StepMountDvdDrive struct {
Expand All @@ -17,7 +19,21 @@ func (s *StepMountDvdDrive) Run(state multistep.StateBag) multistep.StepAction {

errorMsg := "Error mounting dvd drive: %s"
vmName := state.Get("vmName").(string)
isoPath := state.Get("iso_path").(string)

// Determine if we even have a dvd disk to attach
var isoPath string
if isoPathRaw, ok := state.GetOk("iso_path"); ok {
isoPath = isoPathRaw.(string)
} else {
log.Println("No dvd disk, not attaching.")
return multistep.ActionContinue
}

// Determine if its a virtual hdd to mount
if strings.ToLower(filepath.Ext(isoPath)) == ".vhd" || strings.ToLower(filepath.Ext(isoPath)) == ".vhdx" {
log.Println("Its a hard disk, not attaching.")
return multistep.ActionContinue
}

// should be able to mount up to 60 additional iso images using SCSI
// but Windows would only allow a max of 22 due to available drive letters
Expand Down
13 changes: 9 additions & 4 deletions builder/hyperv/iso/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"log"
"os"
"path/filepath"
"strings"

hypervcommon "github.com/hashicorp/packer/builder/hyperv/common"
Expand Down Expand Up @@ -124,9 +125,12 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
errs = packer.MultiErrorAppend(errs, b.config.SSHConfig.Prepare(&b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.ShutdownConfig.Prepare(&b.config.ctx)...)

err = b.checkDiskSize()
if err != nil {
errs = packer.MultiErrorAppend(errs, err)
if len(b.config.ISOConfig.ISOUrls) < 1 || (strings.ToLower(filepath.Ext(b.config.ISOConfig.ISOUrls[0])) != ".vhd" && strings.ToLower(filepath.Ext(b.config.ISOConfig.ISOUrls[0])) != ".vhdx") {
//We only create a new hard drive if an existing one to copy from does not exist
err = b.checkDiskSize()
if err != nil {
errs = packer.MultiErrorAppend(errs, err)
}
}

err = b.checkRamSize()
Expand All @@ -148,7 +152,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
b.config.Cpu = 1
}

if b.config.Generation != 2 {
if b.config.Generation < 1 || b.config.Generation > 2 {
b.config.Generation = 1
}

Expand All @@ -163,6 +167,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
log.Println(fmt.Sprintf("%s: %v", "SwitchName", b.config.SwitchName))

// Errors

if b.config.GuestAdditionsMode == "" {
if b.config.GuestAdditionsPath != "" {
b.config.GuestAdditionsMode = "attach"
Expand Down
Loading

0 comments on commit f3c3324

Please sign in to comment.