diff --git a/builder/hyperv/common/driver.go b/builder/hyperv/common/driver.go index 2a2f0b810..571214acd 100644 --- a/builder/hyperv/common/driver.go +++ b/builder/hyperv/common/driver.go @@ -52,6 +52,8 @@ type Driver interface { //Set the vlan to use for machine SetVirtualMachineVlanId(string, string) error + SetVmNetworkAdapterMacAddress(string, string) error + UntagVirtualMachineNetworkAdapterVlan(string, string) error CreateExternalVirtualSwitch(string, string) error diff --git a/builder/hyperv/common/driver_mock.go b/builder/hyperv/common/driver_mock.go index 3823cbd12..7d8e02c6a 100644 --- a/builder/hyperv/common/driver_mock.go +++ b/builder/hyperv/common/driver_mock.go @@ -67,6 +67,11 @@ type DriverMock struct { SetNetworkAdapterVlanId_VlanId string SetNetworkAdapterVlanId_Err error + SetVmNetworkAdapterMacAddress_Called bool + SetVmNetworkAdapterMacAddress_VmName string + SetVmNetworkAdapterMacAddress_Mac string + SetVmNetworkAdapterMacAddress_Err error + SetVirtualMachineVlanId_Called bool SetVirtualMachineVlanId_VmName string SetVirtualMachineVlanId_VlanId string @@ -318,6 +323,13 @@ func (d *DriverMock) SetNetworkAdapterVlanId(switchName string, vlanId string) e return d.SetNetworkAdapterVlanId_Err } +func (d *DriverMock) SetVmNetworkAdapterMacAddress(vmName string, mac string) error { + d.SetVmNetworkAdapterMacAddress_Called = true + d.SetVmNetworkAdapterMacAddress_VmName = vmName + d.SetVmNetworkAdapterMacAddress_Mac = mac + return d.SetVmNetworkAdapterMacAddress_Err +} + func (d *DriverMock) SetVirtualMachineVlanId(vmName string, vlanId string) error { d.SetVirtualMachineVlanId_Called = true d.SetVirtualMachineVlanId_VmName = vmName diff --git a/builder/hyperv/common/driver_ps_4.go b/builder/hyperv/common/driver_ps_4.go index 853aa7021..a6c1b7352 100644 --- a/builder/hyperv/common/driver_ps_4.go +++ b/builder/hyperv/common/driver_ps_4.go @@ -146,6 +146,10 @@ func (d *HypervPS4Driver) SetVirtualMachineVlanId(vmName string, vlanId string) return hyperv.SetVirtualMachineVlanId(vmName, vlanId) } +func (d *HypervPS4Driver) SetVmNetworkAdapterMacAddress(vmName string, mac string) error { + return hyperv.SetVmNetworkAdapterMacAddress(vmName, mac) +} + func (d *HypervPS4Driver) UntagVirtualMachineNetworkAdapterVlan(vmName string, switchName string) error { return hyperv.UntagVirtualMachineNetworkAdapterVlan(vmName, switchName) } diff --git a/builder/hyperv/common/step_clone_vm.go b/builder/hyperv/common/step_clone_vm.go index f6dc9e390..cca0ac5ab 100644 --- a/builder/hyperv/common/step_clone_vm.go +++ b/builder/hyperv/common/step_clone_vm.go @@ -28,6 +28,7 @@ type StepCloneVM struct { EnableDynamicMemory bool EnableSecureBoot bool EnableVirtualizationExtensions bool + MacAddress string } func (s *StepCloneVM) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { @@ -118,6 +119,16 @@ func (s *StepCloneVM) Run(_ context.Context, state multistep.StateBag) multistep } } + if s.MacAddress != "" { + err = driver.SetVmNetworkAdapterMacAddress(s.VMName, s.MacAddress) + if err != nil { + err := fmt.Errorf("Error setting MAC address: %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) diff --git a/builder/hyperv/common/step_create_vm.go b/builder/hyperv/common/step_create_vm.go index a68965afe..f046d1a48 100644 --- a/builder/hyperv/common/step_create_vm.go +++ b/builder/hyperv/common/step_create_vm.go @@ -29,6 +29,7 @@ type StepCreateVM struct { EnableVirtualizationExtensions bool AdditionalDiskSize []uint DifferencingDisk bool + MacAddress string SkipExport bool OutputDir string } @@ -133,6 +134,16 @@ func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multiste } } + if s.MacAddress != "" { + err = driver.SetVmNetworkAdapterMacAddress(s.VMName, s.MacAddress) + if err != nil { + err := fmt.Errorf("Error setting MAC address: %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) diff --git a/builder/hyperv/iso/builder.go b/builder/hyperv/iso/builder.go index 84d86867c..b92e779df 100644 --- a/builder/hyperv/iso/builder.go +++ b/builder/hyperv/iso/builder.go @@ -74,6 +74,7 @@ type Config struct { BootCommand []string `mapstructure:"boot_command"` SwitchName string `mapstructure:"switch_name"` SwitchVlanId string `mapstructure:"switch_vlan_id"` + MacAddress string `mapstructure:"mac_address"` VlanId string `mapstructure:"vlan_id"` Cpu uint `mapstructure:"cpu"` Generation uint `mapstructure:"generation"` diff --git a/builder/hyperv/vmcx/builder.go b/builder/hyperv/vmcx/builder.go index 1f5ed8df9..8309759fb 100644 --- a/builder/hyperv/vmcx/builder.go +++ b/builder/hyperv/vmcx/builder.go @@ -82,6 +82,7 @@ type Config struct { BootCommand []string `mapstructure:"boot_command"` SwitchName string `mapstructure:"switch_name"` SwitchVlanId string `mapstructure:"switch_vlan_id"` + MacAddress string `mapstructure:"mac_address"` VlanId string `mapstructure:"vlan_id"` Cpu uint `mapstructure:"cpu"` Generation uint @@ -405,6 +406,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe EnableDynamicMemory: b.config.EnableDynamicMemory, EnableSecureBoot: b.config.EnableSecureBoot, EnableVirtualizationExtensions: b.config.EnableVirtualizationExtensions, + MacAddress: b.config.MacAddress, }, &hypervcommon.StepEnableIntegrationService{}, diff --git a/common/powershell/hyperv/hyperv.go b/common/powershell/hyperv/hyperv.go index 25073d238..d26ec5eeb 100644 --- a/common/powershell/hyperv/hyperv.go +++ b/common/powershell/hyperv/hyperv.go @@ -319,6 +319,18 @@ Copy-Item $cloneFromVmxcPath $exportPath -Recurse -Force return err } +func SetVmNetworkAdapterMacAddress(vmName string, mac string) error { + var script = ` +param([string]$vmName, [string]$mac) +Set-VMNetworkAdapter $vmName -staticmacaddress $mac + ` + + var ps powershell.PowerShellCmd + err := ps.Run(script, vmName, mac) + + return err +} + func ImportVmxcVirtualMachine(importPath string, vmName string, harddrivePath string, ram int64, switchName string) error { var script = ` param([string]$importPath, [string]$vmName, [string]$harddrivePath, [long]$memoryStartupBytes, [string]$switchName) diff --git a/website/source/docs/builders/hyperv-iso.html.md b/website/source/docs/builders/hyperv-iso.html.md index 24fee6f05..e1454fea7 100644 --- a/website/source/docs/builders/hyperv-iso.html.md +++ b/website/source/docs/builders/hyperv-iso.html.md @@ -210,7 +210,7 @@ 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`. -* `vhd_temp_path` (string) - A separate path to be used for storing the VM's +- `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 path while exporting the VM) to eliminate a single-disk bottleneck. @@ -219,6 +219,10 @@ can be configured for this builder. for the new virtual machine. By default none is set. If none is set then vlans are not set on the virtual machine's network card. +- `mac_address` (string) - This allows a specific MAC address to be used on the + default virtual network card. The MAC address must be a string with no + delimeters, for example "0000deadbeef". + - `vm_name` (string) - This is the name of the virtual machine for the new virtual machine, without the file extension. By default this is "packer-BUILDNAME", where "BUILDNAME" is the name of the build. diff --git a/website/source/docs/builders/hyperv-vmcx.html.md b/website/source/docs/builders/hyperv-vmcx.html.md index 1aac29fc1..a7afe93ce 100644 --- a/website/source/docs/builders/hyperv-vmcx.html.md +++ b/website/source/docs/builders/hyperv-vmcx.html.md @@ -225,6 +225,10 @@ can be configured for this builder. for the new virtual machine. By default none is set. If none is set then vlans are not set on the virtual machine's network card. +- `mac_address` (string) - This allows a specific MAC address to be used on the + default virtual network card. The MAC address must be a string with no + delimeters, for example "0000deadbeef". + - `vm_name` (string) - This is the name of the virtual machine for the new virtual machine, without the file extension. By default this is "packer-BUILDNAME", where "BUILDNAME" is the name of the build.