Using vmconnect to display gui for hyper-v

vmconnect.exe comes as part of Hyper-V and is the tool used by Hyper-V Manager to connect with a virtual machine. This commits sets behaviour the same as virtualbox and vmware to display the virtual machine connection unless headless is set in the template.
This commit is contained in:
Unknown 2018-05-06 07:54:58 +10:00 committed by Cameron Jack
parent 132dfa7c86
commit fc734b6bd9
9 changed files with 90 additions and 3 deletions

View File

@ -1,5 +1,9 @@
package common
import (
"context"
)
// A driver is able to talk to HyperV and perform certain
// operations with it. Some of the operations on here may seem overly
// specific, but they were built specifically in mind to handle features
@ -109,4 +113,10 @@ type Driver interface {
MountFloppyDrive(string, string) error
UnmountFloppyDrive(string) error
// Connect connects to a VM specified by the name given.
Connect(string) context.CancelFunc
// Disconnect disconnects to a VM specified by the context cancel function.
Disconnect(context.CancelFunc)
}

View File

@ -1,5 +1,9 @@
package common
import (
"context"
)
type DriverMock struct {
IsRunning_Called bool
IsRunning_VmName string
@ -240,6 +244,13 @@ type DriverMock struct {
UnmountFloppyDrive_Called bool
UnmountFloppyDrive_VmName string
UnmountFloppyDrive_Err error
Connect_Called bool
Connect_VmName string
Connect_Cancel context.CancelFunc
Disconnect_Called bool
Disconnect_Cancel context.CancelFunc
}
func (d *DriverMock) IsRunning(vmName string) (bool, error) {
@ -553,3 +564,14 @@ func (d *DriverMock) UnmountFloppyDrive(vmName string) error {
d.UnmountFloppyDrive_VmName = vmName
return d.UnmountFloppyDrive_Err
}
func (d *DriverMock) Connect(vmName string) context.CancelFunc {
d.Connect_Called = true
d.Connect_VmName = vmName
return d.Connect_Cancel
}
func (d *DriverMock) Disconnect(cancel context.CancelFunc) {
d.Disconnect_Called = true
d.Disconnect_Cancel = cancel
}

View File

@ -1,6 +1,7 @@
package common
import (
"context"
"fmt"
"log"
"runtime"
@ -347,3 +348,14 @@ func (d *HypervPS4Driver) verifyHypervPermissions() error {
return nil
}
// Connect connects to a VM specified by the name given.
func (d *HypervPS4Driver) Connect(vmName string) context.CancelFunc {
return hyperv.ConnectVirtualMachine(vmName)
}
// Disconnect disconnects to a VM specified by calling the context cancel function returned
// from Connect.
func (d *HypervPS4Driver) Disconnect(cancel context.CancelFunc) {
hyperv.DisconnectVirtualMachine(cancel)
}

View File

@ -9,7 +9,8 @@ import (
)
type StepRun struct {
vmName string
Headless bool
vmName string
}
func (s *StepRun) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
@ -29,6 +30,11 @@ func (s *StepRun) Run(_ context.Context, state multistep.StateBag) multistep.Ste
s.vmName = vmName
if !s.Headless {
ui.Say("Connecting to vmconnect...")
cancel := driver.Connect(vmName)
state.Put("guiCancelFunc", cancel)
}
return multistep.ActionContinue
}
@ -39,6 +45,12 @@ func (s *StepRun) Cleanup(state multistep.StateBag) {
driver := state.Get("driver").(Driver)
ui := state.Get("ui").(packer.Ui)
guiCancelFunc := state.Get("guiCancelFunc").(context.CancelFunc)
if guiCancelFunc != nil {
ui.Say("Disconnecting from vmconnect...")
guiCancelFunc()
}
if running, _ := driver.IsRunning(s.vmName); running {
if err := driver.Stop(s.vmName); err != nil {

View File

@ -115,6 +115,8 @@ type Config struct {
// Create the VM with a Fixed VHD format disk instead of Dynamic VHDX
FixedVHD bool `mapstructure:"use_fixed_vhd_format"`
Headless bool `mapstructure:"headless"`
ctx interpolate.Context
}
@ -427,7 +429,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
SwitchVlanId: b.config.SwitchVlanId,
},
&hypervcommon.StepRun{},
&hypervcommon.StepRun{
Headless: b.config.Headless,
},
&hypervcommon.StepTypeBootCommand{
BootCommand: b.config.FlatBootCommand(),

View File

@ -98,6 +98,8 @@ type Config struct {
SkipExport bool `mapstructure:"skip_export"`
Headless bool `mapstructure:"headless"`
ctx interpolate.Context
}
@ -436,7 +438,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
SwitchVlanId: b.config.SwitchVlanId,
},
&hypervcommon.StepRun{},
&hypervcommon.StepRun{
Headless: b.config.Headless,
},
&hypervcommon.StepTypeBootCommand{
BootCommand: b.config.FlatBootCommand(),

View File

@ -1,7 +1,9 @@
package hyperv
import (
"context"
"errors"
"os/exec"
"strconv"
"strings"
@ -1244,3 +1246,14 @@ param([string]$vmName, [string]$scanCodes)
err := ps.Run(script, vmName, scanCodes)
return err
}
func ConnectVirtualMachine(vmName string) context.CancelFunc {
ctx, cancel := context.WithCancel(context.Background())
cmd := exec.CommandContext(ctx, "vmconnect.exe", "localhost", vmName)
cmd.Start()
return cancel
}
func DisconnectVirtualMachine(cancel context.CancelFunc) {
cancel()
}

View File

@ -102,6 +102,11 @@ can be configured for this builder.
- `differencing_disk` (boolean) - If true enables differencing disks. Only the changes will be written to the new disk. This is especially useful if your
source is a vhd/vhdx. This defaults to false.
- `headless` (boolean) - Packer defaults to building Hyper-V virtual
machines by launching a GUI that shows the console of the machine
being built. When this value is set to true, the machine will start without
a console.
- `skip_export` (boolean) - If true skips VM export. If you are interested only in the vhd/vhdx files, you can enable this option. This will create
inline disks which improves the build performance. There will not be any copying of source vhds to temp directory. This defaults to false.

View File

@ -139,6 +139,11 @@ can be configured for this builder.
- `guest_additions_path` (string) - The path to the iso image for guest
additions.
- `headless` (boolean) - Packer defaults to building Hyper-V virtual
machines by launching a GUI that shows the console of the machine
being built. When this value is set to true, the machine will start without
a console.
- `http_directory` (string) - Path to a directory to serve using an HTTP
server. The files in this directory will be available over HTTP that will
be requestable from the virtual machine. This is useful for hosting