Add support for mac spoofing and dynamic memory.

To enable nested virtualization, mac spoofing, no dynamic memory and at least 4gb of ram should be set for the vm. Set warning if this has not been done.
Detected Virtualization Extensions are supported by the machine your are running on, as it only works for Windows 10 and Windows Server 2016 onwards.
This commit is contained in:
Taliesin Sisson 2016-08-07 12:26:27 +01:00
parent 1277a25d0b
commit 9fbd1e472a
6 changed files with 192 additions and 48 deletions

View File

@ -72,9 +72,15 @@ type Driver interface {
DeleteVirtualMachine(string) error
SetVirtualMachineCpu(string, uint, bool) error
SetVirtualMachineCpuCount(string, uint) error
SetSecureBoot(string, bool) error
SetVirtualMachineMacSpoofing(string, bool) error
SetVirtualMachineDynamicMemory(string, bool) error
SetVirtualMachineSecureBoot(string, bool) error
SetVirtualMachineVirtualizationExtensions(string, bool) error
EnableVirtualMachineIntegrationService(string, string) error

View File

@ -6,12 +6,13 @@ package common
import (
"fmt"
"github.com/mitchellh/packer/powershell"
"github.com/mitchellh/packer/powershell/hyperv"
"log"
"runtime"
"strconv"
"strings"
"github.com/mitchellh/packer/powershell"
"github.com/mitchellh/packer/powershell/hyperv"
)
type HypervPS4Driver struct {
@ -177,12 +178,24 @@ func (d *HypervPS4Driver) DeleteVirtualMachine(vmName string) error {
return hyperv.DeleteVirtualMachine(vmName)
}
func (d *HypervPS4Driver) SetVirtualMachineCpu(vmName string, cpu uint, exposeVirtualizationExtensions bool) error {
return hyperv.SetVirtualMachineCpu(vmName, cpu, exposeVirtualizationExtensions)
func (d *HypervPS4Driver) SetVirtualMachineCpuCount(vmName string, cpu uint) error {
return hyperv.SetVirtualMachineCpuCount(vmName, cpu)
}
func (d *HypervPS4Driver) SetSecureBoot(vmName string, enable bool) error {
return hyperv.SetSecureBoot(vmName, enable)
func (d *HypervPS4Driver) SetVirtualMachineMacSpoofing(vmName string, enable bool) error {
return hyperv.SetVirtualMachineMacSpoofing(vmName, enable)
}
func (d *HypervPS4Driver) SetVirtualMachineDynamicMemory(vmName string, enable bool) error {
return hyperv.SetVirtualMachineDynamicMemory(vmName, enable)
}
func (d *HypervPS4Driver) SetVirtualMachineSecureBoot(vmName string, enable bool) error {
return hyperv.SetVirtualMachineSecureBoot(vmName, enable)
}
func (d *HypervPS4Driver) SetVirtualMachineVirtualizationExtensions(vmName string, enable bool) error {
return hyperv.SetVirtualMachineVirtualizationExtensions(vmName, enable)
}
func (d *HypervPS4Driver) EnableVirtualMachineIntegrationService(vmName string, integrationServiceName string) error {

View File

@ -6,6 +6,7 @@ package common
import (
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
)
@ -15,13 +16,15 @@ import (
// Produces:
// VMName string - The name of the VM
type StepCreateVM struct {
VMName string
SwitchName string
RamSizeMB uint
DiskSize uint
Generation uint
Cpu uint
EnableSecureBoot bool
VMName string
SwitchName string
RamSizeMB uint
DiskSize uint
Generation uint
Cpu uint
EnableMacSpoofing bool
EnableDynamicMemory bool
EnableSecureBoot bool
EnableVirtualizationExtensions bool
}
@ -36,10 +39,7 @@ func (s *StepCreateVM) Run(state multistep.StateBag) multistep.StepAction {
ram := int64(s.RamSizeMB * 1024 * 1024)
diskSize := int64(s.DiskSize * 1024 * 1024)
switchName := s.SwitchName
enableSecureBoot := s.EnableSecureBoot
err := driver.CreateVirtualMachine(s.VMName, path, ram, diskSize, switchName, s.Generation)
err := driver.CreateVirtualMachine(s.VMName, path, ram, diskSize, s.SwitchName, s.Generation)
if err != nil {
err := fmt.Errorf("Error creating virtual machine: %s", err)
state.Put("error", err)
@ -47,7 +47,7 @@ func (s *StepCreateVM) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionHalt
}
err = driver.SetVirtualMachineCpu(s.VMName, s.Cpu, s.EnableVirtualizationExtensions)
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)
@ -55,8 +55,28 @@ func (s *StepCreateVM) Run(state multistep.StateBag) multistep.StepAction {
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
}
}
if s.Generation == 2 {
err = driver.SetSecureBoot(s.VMName, enableSecureBoot)
err = driver.SetVirtualMachineSecureBoot(s.VMName, s.EnableSecureBoot)
if err != nil {
err := fmt.Errorf("Error setting secure boot: %s", err)
state.Put("error", err)
@ -65,6 +85,17 @@ func (s *StepCreateVM) Run(state multistep.StateBag) multistep.StepAction {
}
}
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)

View File

@ -28,9 +28,10 @@ const (
MinDiskSize = 256 // 256MB
MaxDiskSize = 64 * 1024 * 1024 // 64TB
DefaultRamSize = 1 * 1024 // 1GB
MinRamSize = 32 // 32MB
MaxRamSize = 32 * 1024 // 32GB
DefaultRamSize = 1 * 1024 // 1GB
MinRamSize = 32 // 32MB
MaxRamSize = 32 * 1024 // 32GB
MinNestedVirtualizationRamSize = 4 * 1024 // 4GB
LowRam = 256 // 256MB
@ -84,12 +85,14 @@ type Config struct {
// By default this is "packer-BUILDNAME", where "BUILDNAME" is the name of the build.
VMName string `mapstructure:"vm_name"`
BootCommand []string `mapstructure:"boot_command"`
SwitchName string `mapstructure:"switch_name"`
Cpu uint `mapstructure:"cpu"`
Generation uint `mapstructure:"generation"`
EnableSecureBoot bool `mapstructure:"enable_secure_boot"`
EnableVirtualizationExtensions bool `mapstructure:"enable_virtualization_extensions"`
BootCommand []string `mapstructure:"boot_command"`
SwitchName string `mapstructure:"switch_name"`
Cpu uint `mapstructure:"cpu"`
Generation uint `mapstructure:"generation"`
EnableMacSpoofing bool `mapstructure:"enable_mac_spoofing"`
EnableDynamicMemory bool `mapstructure:"enable_dynamic_memory"`
EnableSecureBoot bool `mapstructure:"enable_secure_boot"`
EnableVirtualizationExtensions bool `mapstructure:"enable_virtualization_extensions"`
Communicator string `mapstructure:"communicator"`
@ -227,6 +230,17 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
}
}
if b.config.EnableVirtualizationExtensions {
hasVirtualMachineVirtualizationExtensions, err := powershell.HasVirtualMachineVirtualizationExtensions()
if err != nil {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("Failed detecting virtual machine virtualization extensions support: %s", err))
} else {
if !hasVirtualMachineVirtualizationExtensions {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("This version of Hyper-V does not support virtual machine virtualization extension. Please use Windows 10 or Windows Server 2016 or newer."))
}
}
}
// Warnings
if b.config.ShutdownCommand == "" {
@ -240,6 +254,23 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
warnings = appendWarnings(warnings, warning)
}
if b.config.EnableVirtualizationExtensions {
if b.config.EnableDynamicMemory {
warning = fmt.Sprintf("For nested virtualization, when virtualization extension is enabled, dynamic memory should not be allowed.")
warnings = appendWarnings(warnings, warning)
}
if !b.config.EnableMacSpoofing {
warning = fmt.Sprintf("For nested virtualization, when virtualization extension is enabled, mac spoofing should be allowed.")
warnings = appendWarnings(warnings, warning)
}
if b.config.RamSizeMB < MinNestedVirtualizationRamSize {
warning = fmt.Sprintf("For nested virtualization, when virtualization extension is enabled, there should be 4GB or more memory set for the vm, otherwise Hyper-V may fail to start any nested VMs.")
warnings = appendWarnings(warnings, warning)
}
}
if errs != nil && len(errs.Errors) > 0 {
return warnings, errs
}
@ -292,13 +323,15 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
SwitchName: b.config.SwitchName,
},
&hypervcommon.StepCreateVM{
VMName: b.config.VMName,
SwitchName: b.config.SwitchName,
RamSizeMB: b.config.RamSizeMB,
DiskSize: b.config.DiskSize,
Generation: b.config.Generation,
Cpu: b.config.Cpu,
EnableSecureBoot: b.config.EnableSecureBoot,
VMName: b.config.VMName,
SwitchName: b.config.SwitchName,
RamSizeMB: b.config.RamSizeMB,
DiskSize: b.config.DiskSize,
Generation: b.config.Generation,
Cpu: b.config.Cpu,
EnableMacSpoofing: b.config.EnableMacSpoofing,
EnableDynamicMemory: b.config.EnableDynamicMemory,
EnableSecureBoot: b.config.EnableSecureBoot,
EnableVirtualizationExtensions: b.config.EnableVirtualizationExtensions,
},
&hypervcommon.StepEnableIntegrationService{},

View File

@ -217,23 +217,67 @@ New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -NewVHD
}
}
func SetVirtualMachineCpu(vmName string, cpu uint, enableVirtualizationExtensions bool) error {
func SetVirtualMachineCpuCount(vmName string, cpu uint) error {
var script = `
param([string]$vmName, [int]$cpu, [string]$exposeVirtualizationExtensions)
$nested = [System.Boolean]::Parse($exposeVirtualizationExtensions)
Set-VMProcessor -VMName $vmName -Count $cpu -exposeVirtualizationExtensions $nested
param([string]$vmName, [int]$cpu)
Set-VMProcessor -VMName $vmName -Count $cpu
`
var ps powershell.PowerShellCmd
err := ps.Run(script, vmName, strconv.FormatInt(int64(cpu), 10))
return err
}
func SetVirtualMachineVirtualizationExtensions(vmName string, enableVirtualizationExtensions bool) error {
var script = `
param([string]$vmName, [string]$exposeVirtualizationExtensionsString)
$exposeVirtualizationExtensions = [System.Boolean]::Parse($exposeVirtualizationExtensionsString)
Set-VMProcessor -VMName $vmName -ExposeVirtualizationExtensions $exposeVirtualizationExtensions
`
exposeVirtualizationExtensionsString := "False"
if enableVirtualizationExtensions {
exposeVirtualizationExtensionsString = "True"
}
}
var ps powershell.PowerShellCmd
err := ps.Run(script, vmName, strconv.FormatInt(int64(cpu), 10), exposeVirtualizationExtensionsString)
err := ps.Run(script, vmName, exposeVirtualizationExtensionsString)
return err
}
func SetSecureBoot(vmName string, enable bool) error {
func SetVirtualMachineDynamicMemory(vmName string, enableDynamicMemory bool) error {
var script = `
param([string]$vmName, [string]$enableDynamicMemoryString)
$enableDynamicMemory = [System.Boolean]::Parse($enableDynamicMemoryString)
Set-VMMemory -VMName $vmName -DynamicMemoryEnabled $enableDynamicMemory
`
enableDynamicMemoryString := "False"
if enableDynamicMemory {
enableDynamicMemoryString = "True"
}
var ps powershell.PowerShellCmd
err := ps.Run(script, vmName, enableDynamicMemoryString)
return err
}
func SetVirtualMachineMacSpoofing(vmName string, enableMacSpoofing bool) error {
var script = `
param([string]$vmName, $enableMacSpoofing)
Set-VMNetworkAdapter -VMName $vmName -MacAddressSpoofing $enableMacSpoofing
`
var ps powershell.PowerShellCmd
enableMacSpoofingString := "Off"
if enableMacSpoofing {
enableMacSpoofingString = "On"
}
err := ps.Run(script, vmName, enableMacSpoofingString)
return err
}
func SetVirtualMachineSecureBoot(vmName string, enableSecureBoot bool) error {
var script = `
param([string]$vmName, $enableSecureBoot)
Set-VMFirmware -VMName $vmName -EnableSecureBoot $enableSecureBoot
@ -241,12 +285,12 @@ Set-VMFirmware -VMName $vmName -EnableSecureBoot $enableSecureBoot
var ps powershell.PowerShellCmd
enableSecureBoot := "Off"
if enable {
enableSecureBoot = "On"
enableSecureBootString := "Off"
if enableSecureBoot {
enableSecureBootString = "On"
}
err := ps.Run(script, vmName, enableSecureBoot)
err := ps.Run(script, vmName, enableSecureBootString)
return err
}

View File

@ -231,6 +231,23 @@ param([string]$moduleName)
return true, nil
}
func HasVirtualMachineVirtualizationExtensions() (bool, error) {
var script = `
(GET-Command Set-VMProcessor).parameters.keys -contains "ExposeVirtualizationExtensions"
`
var ps PowerShellCmd
cmdOut, err := ps.Output(script)
if err != nil {
return false, err
}
var hasVirtualMachineVirtualizationExtensions = strings.TrimSpace(cmdOut) == "True"
return hasVirtualMachineVirtualizationExtensions, err
}
func SetUnattendedProductKey(path string, productKey string) error {
var script = `