diff --git a/builder/hyperv/common/driver.go b/builder/hyperv/common/driver.go index 9446c0410a9..d6cb7014198 100644 --- a/builder/hyperv/common/driver.go +++ b/builder/hyperv/common/driver.go @@ -52,6 +52,9 @@ type Driver interface { //Set the vlan to use for machine SetVirtualMachineVlanId(string, string) error + //Replace the network adapter with a (non-)legacy adapter + ReplaceVirtualMachineNetworkAdapter(string, bool) error + UntagVirtualMachineNetworkAdapterVlan(string, string) error CreateExternalVirtualSwitch(string, string) error diff --git a/builder/hyperv/common/driver_ps_4.go b/builder/hyperv/common/driver_ps_4.go index 030ee8f5559..bb2e6a23d37 100644 --- a/builder/hyperv/common/driver_ps_4.go +++ b/builder/hyperv/common/driver_ps_4.go @@ -142,6 +142,11 @@ func (d *HypervPS4Driver) SetVirtualMachineVlanId(vmName string, vlanId string) return hyperv.SetVirtualMachineVlanId(vmName, vlanId) } +//Replace the network adapter with a (non-)legacy adapter +func (d *HypervPS4Driver) ReplaceVirtualMachineNetworkAdapter(vmName string, virtual bool) error { + return hyperv.ReplaceVirtualMachineNetworkAdapter(vmName, virtual) +} + func (d *HypervPS4Driver) UntagVirtualMachineNetworkAdapterVlan(vmName string, switchName string) error { return hyperv.UntagVirtualMachineNetworkAdapterVlan(vmName, switchName) } diff --git a/builder/hyperv/common/step_create_vm.go b/builder/hyperv/common/step_create_vm.go index 9fa65b1a86e..fe5a73cb23a 100644 --- a/builder/hyperv/common/step_create_vm.go +++ b/builder/hyperv/common/step_create_vm.go @@ -22,6 +22,7 @@ type StepCreateVM struct { EnableDynamicMemory bool EnableSecureBoot bool EnableVirtualizationExtensions bool + UseLegacyNetworkAdapter bool } func (s *StepCreateVM) Run(state multistep.StateBag) multistep.StepAction { @@ -43,6 +44,16 @@ func (s *StepCreateVM) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionHalt } + if s.UseLegacyNetworkAdapter { + err := driver.ReplaceVirtualMachineNetworkAdapter(s.VMName, true) + if err != nil { + err := fmt.Errorf("Error creating legacy network adapter: %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) diff --git a/builder/hyperv/iso/builder.go b/builder/hyperv/iso/builder.go index ede06cca00d..54383260d80 100644 --- a/builder/hyperv/iso/builder.go +++ b/builder/hyperv/iso/builder.go @@ -90,6 +90,7 @@ type Config struct { EnableDynamicMemory bool `mapstructure:"enable_dynamic_memory"` EnableSecureBoot bool `mapstructure:"enable_secure_boot"` EnableVirtualizationExtensions bool `mapstructure:"enable_virtualization_extensions"` + UseLegacyNetworkAdapter bool `mapstructure:"use_legacy_network_adapter"` Communicator string `mapstructure:"communicator"` @@ -160,6 +161,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { err = errors.New("Generation 2 vms don't support floppy drives. Use ISO image instead.") errs = packer.MultiErrorAppend(errs, err) } + if b.config.UseLegacyNetworkAdapter { + err = errors.New("Generation 2 vms don't support legacy network adapters.") + errs = packer.MultiErrorAppend(errs, err) + } } log.Println(fmt.Sprintf("Using switch %s", b.config.SwitchName)) @@ -339,6 +344,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, + UseLegacyNetworkAdapter: b.config.UseLegacyNetworkAdapter, }, &hypervcommon.StepEnableIntegrationService{}, diff --git a/builder/hyperv/iso/builder_test.go b/builder/hyperv/iso/builder_test.go index 3adf05aa9ad..7722f468341 100644 --- a/builder/hyperv/iso/builder_test.go +++ b/builder/hyperv/iso/builder_test.go @@ -248,3 +248,32 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) { t.Fatalf("bad: %#v", b.config.ISOUrls) } } + +func TestBuilderPrepare_UseLegacyNetworkAdapter(t *testing.T) { + var b Builder + config := testConfig() + + // should be allowed for default config + config["use_legacy_network_adapter"] = true + + b = Builder{} + warns, err := b.Prepare(config) + if len(warns) > 0 { + t.Fatalf("bad: %#v", warns) + } + if err != nil { + t.Errorf("should not have error: %s", err) + } + + // should not be allowed for gen 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") + } +} diff --git a/common/powershell/hyperv/hyperv.go b/common/powershell/hyperv/hyperv.go index e57a98f0dd7..e4c9d125c0f 100644 --- a/common/powershell/hyperv/hyperv.go +++ b/common/powershell/hyperv/hyperv.go @@ -571,6 +571,24 @@ Set-VMNetworkAdapterVlan -VMName $vmName -Access -VlanId $vlanId return err } +func ReplaceVirtualMachineNetworkAdapter(vmName string, legacy bool) error { + + var script = ` +param([string]$vmName,[string]$legacyString) +$legacy = [System.Boolean]::Parse($legacyString) +$switch = (Get-VMNetworkAdapter -VMName $vmName).SwitchName +Remove-VMNetworkAdapter -VMName $vmName +Add-VMNetworkAdapter -VMName $vmName -SwitchName $switch -Name $vmName -IsLegacy $legacy +` + legacyString := "False" + if legacy { + legacyString = "True" + } + var ps powershell.PowerShellCmd + err := ps.Run(script, vmName, legacyString) + return err +} + func GetExternalOnlineVirtualSwitch() (string, error) { var script = ` diff --git a/website/source/docs/builders/hyperv-iso.html.md b/website/source/docs/builders/hyperv-iso.html.md index 08cb732a450..6ad6f7e64a2 100644 --- a/website/source/docs/builders/hyperv-iso.html.md +++ b/website/source/docs/builders/hyperv-iso.html.md @@ -195,6 +195,9 @@ can be configured for this builder. machine, without the file extension. By default this is "packer-BUILDNAME", where "BUILDNAME" is the name of the build. +- `use_legacy_network_adapter` (bool) - If true use a legacy network adapter as the NIC. + This defaults to false. + ## Boot Command The `boot_command` configuration is very important: it specifies the keys