Allow configurable VNC bind IP for QEMU

This commit allows for a user configurable VNC bind IP to be used for
QEMU.

By default this will be 127.0.0.1, alternatively, a user can use
0.0.0.0 which will bind to all interfaces.

This pull request should satisfy concerns of #3570 and #3559. It is
also in-line with the functionality provided by #3566 and #3565

Signed-off-by: Ian Duffy <ian@ianduffy.ie>
This commit is contained in:
Ian Duffy 2016-05-25 10:10:12 +01:00
parent 7759229b9d
commit fa273f3bea
5 changed files with 50 additions and 7 deletions

View File

@ -104,6 +104,7 @@ type Config struct {
ShutdownCommand string `mapstructure:"shutdown_command"`
SSHHostPortMin uint `mapstructure:"ssh_host_port_min"`
SSHHostPortMax uint `mapstructure:"ssh_host_port_max"`
VNCBindAddress string `mapstructure:"vnc_bind_address"`
VNCPortMin uint `mapstructure:"vnc_port_min"`
VNCPortMax uint `mapstructure:"vnc_port_max"`
VMName string `mapstructure:"vm_name"`
@ -194,6 +195,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
b.config.SSHHostPortMax = 4444
}
if b.config.VNCBindAddress == "" {
b.config.VNCBindAddress = "127.0.0.1"
}
if b.config.VNCPortMin == 0 {
b.config.VNCPortMin = 5900
}

View File

@ -132,6 +132,25 @@ func TestBuilderPrepare_BootWait(t *testing.T) {
}
}
func TestBuilderPrepare_VNCBindAddress(t *testing.T) {
var b Builder
config := testConfig()
// Test a default boot_wait
delete(config, "vnc_bind_address")
warns, err := b.Prepare(config)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("err: %s", err)
}
if b.config.VNCBindAddress != "127.0.0.1" {
t.Fatalf("bad value: %s", b.config.VNCBindAddress)
}
}
func TestBuilderPrepare_DiskCompaction(t *testing.T) {
var b Builder
config := testConfig()

View File

@ -26,7 +26,7 @@ func (stepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction {
// Find an open VNC port. Note that this can still fail later on
// because we have to release the port at some point. But this does its
// best.
msg := fmt.Sprintf("Looking for available port between %d and %d", config.VNCPortMin, config.VNCPortMax)
msg := fmt.Sprintf("Looking for available port between %d and %d on %s", config.VNCPortMin, config.VNCPortMax, config.VNCBindAddress)
ui.Say(msg)
log.Printf(msg)
var vncPort uint
@ -39,15 +39,16 @@ func (stepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction {
}
log.Printf("Trying port: %d", vncPort)
l, err := net.Listen("tcp", fmt.Sprintf(":%d", vncPort))
l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", config.VNCBindAddress, vncPort))
if err == nil {
defer l.Close()
break
}
}
ui.Say(fmt.Sprintf("Found available VNC port: %d", vncPort))
log.Printf("Found available VNC port: %d on IP: %s", vncPort, config.VNCBindAddress)
state.Put("vnc_port", vncPort)
state.Put("vnc_ip", config.VNCBindAddress)
return multistep.ActionContinue
}

View File

@ -61,12 +61,13 @@ func (s *stepRun) Cleanup(state multistep.StateBag) {
func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error) {
config := state.Get("config").(*Config)
isoPath := state.Get("iso_path").(string)
vncIP := state.Get("vnc_ip").(string)
vncPort := state.Get("vnc_port").(uint)
sshHostPort := state.Get("sshHostPort").(uint)
ui := state.Get("ui").(packer.Ui)
driver := state.Get("driver").(Driver)
vnc := fmt.Sprintf("0.0.0.0:%d", vncPort-5900)
vnc := fmt.Sprintf("%s:%d", vncIP, vncPort-5900)
vmName := config.VMName
imgPath := filepath.Join(config.OutputDir, vmName)
@ -100,9 +101,22 @@ func getCommandArgs(bootDrive string, state multistep.StateBag) ([]string, error
deviceArgs = append(deviceArgs, fmt.Sprintf("%s,netdev=user.0", config.NetDevice))
if config.Headless == true {
ui.Message("WARNING: The VM will be started in headless mode, as configured.\n" +
"In headless mode, errors during the boot sequence or OS setup\n" +
"won't be easily visible. Use at your own discretion.")
vncIpRaw, vncIpOk := state.GetOk("vnc_ip")
vncPortRaw, vncPortOk := state.GetOk("vnc_port")
if vncIpOk && vncPortOk {
vncIp := vncIpRaw.(string)
vncPort := vncPortRaw.(uint)
ui.Message(fmt.Sprintf(
"The VM will be run headless, without a GUI. If you want to\n"+
"view the screen of the VM, connect via VNC without a password to\n"+
"%s:%d", vncIp, vncPort))
} else {
ui.Message("The VM will be run headless, without a GUI, as configured.\n" +
"If the run isn't succeeding as you expect, please enable the GUI\n" +
"to inspect the progress of the build.")
}
} else {
if qemuMajor >= 2 {
defaultArgs["-display"] = "sdl"

View File

@ -306,6 +306,10 @@ default port of `5985` or whatever value you have the service set to listen on.
`BUILDNAME` is the name of the build. Currently, no file extension will be
used unless it is specified in this option.
- `vnc_bind_address` (string / IP address) - The IP address that should be binded
to for VNC. By default packer will use 127.0.0.1 for this. If you wish to bind
to all interfaces use 0.0.0.0
- `vnc_port_min` and `vnc_port_max` (integer) - The minimum and maximum port
to use for VNC access to the virtual machine. The builder uses VNC to type
the initial `boot_command`. Because Packer generally runs in parallel,